2015-07-15 13:58:20 +00:00
#!/usr/bin/env perl
2023-09-26 20:50:57 +00:00
# mysqltuner.pl - Version 2.3.2
2008-09-08 01:16:39 +00:00
# High Performance MySQL Tuning Script
2023-02-10 06:22:14 +00:00
# Copyright (C) 2015-2023 Jean-Marie Renouard - jmrenouard@gmail.com
2023-08-16 05:38:34 +00:00
# Copyright (C) 2006-2023 Major Hayden - major@mhtx.net
2022-02-12 14:53:33 +00:00
2020-09-03 16:17:58 +00:00
# For the latest updates, please visit http://mysqltuner.pl/
2019-03-22 06:32:47 +00:00
# Git repository available at https://github.com/major/MySQLTuner-perl
2008-09-08 01:16:39 +00:00
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
2023-07-06 06:19:29 +00:00
#
2008-09-08 01:16:39 +00:00
# You should have received a copy of the GNU General Public License
2019-03-22 06:32:47 +00:00
# along with this program. If not, see <https://www.gnu.org/licenses/>.
2008-09-08 01:16:39 +00:00
#
# This project would not be possible without help from:
2009-09-17 23:24:33 +00:00
# Matthew Montgomery Paul Kehrer Dave Burgess
# Jonathan Hinds Mike Jackson Nils Breunese
# Shawn Ashlee Luuk Vosslamber Ville Skytta
# Trent Hornibrook Jason Gill Mark Imbriaco
# Greg Eden Aubin Galinotti Giovanni Bechis
# Bill Bradford Ryan Novosielski Michael Scheidell
# Blair Christensen Hans du Plooy Victor Trac
# Everett Barnes Tom Krouper Gary Barrueto
# Simon Greenaway Adam Stein Isart Montane
2015-06-18 20:02:55 +00:00
# Baptiste M. Cole Turner Major Hayden
2021-07-02 14:22:51 +00:00
# Joe Ashcraft Jean-Marie Renouard Christian Loos
2023-02-28 12:51:46 +00:00
# Julien Francoz Daniel Black Long Radix
2008-09-08 01:16:39 +00:00
#
# Inspired by Matthew Montgomery's tuning-primer.sh script:
2019-03-22 06:32:47 +00:00
# http://www.day32.com/MySQL/
2008-09-08 01:16:39 +00:00
#
2015-08-26 13:23:19 +00:00
package main ;
2015-11-23 07:14:28 +00:00
use 5.005 ;
2008-09-08 01:16:39 +00:00
use strict ;
use warnings ;
2015-11-23 07:14:28 +00:00
2008-09-08 01:16:39 +00:00
use diagnostics ;
2011-04-02 12:03:32 +00:00
use File::Spec ;
2008-09-08 01:16:39 +00:00
use Getopt::Long ;
2017-06-15 18:52:14 +00:00
use Pod::Usage ;
2015-06-12 14:09:59 +00:00
use File::Basename ;
use Cwd 'abs_path' ;
2015-08-26 13:23:19 +00:00
2021-10-15 11:43:07 +00:00
#use Data::Dumper;
#$Data::Dumper::Pair = " : ";
2015-11-23 07:14:28 +00:00
2016-04-18 14:45:34 +00:00
# for which()
2016-04-19 14:11:35 +00:00
#use Env;
2016-04-18 14:45:34 +00:00
2008-09-08 01:16:39 +00:00
# Set up a few variables for use in the script
2023-09-26 20:50:57 +00:00
my $ tunerversion = "2.3.2" ;
2015-08-19 12:45:24 +00:00
my ( @ adjvars , @ generalrec ) ;
2008-09-08 01:16:39 +00:00
# Set defaults
my % opt = (
2022-12-29 04:13:02 +00:00
"silent" = > 0 ,
"nobad" = > 0 ,
"nogood" = > 0 ,
"noinfo" = > 0 ,
"debug" = > 0 ,
"nocolor" = > ( ! - t STDOUT ) ,
"color" = > 0 ,
2023-06-26 07:42:58 +00:00
"forcemem" = > 0 ,
"forceswap" = > 0 ,
2022-12-29 04:13:02 +00:00
"host" = > 0 ,
"socket" = > 0 ,
"port" = > 0 ,
"user" = > 0 ,
"pass" = > 0 ,
"password" = > 0 ,
"ssl-ca" = > 0 ,
"skipsize" = > 0 ,
"checkversion" = > 0 ,
"updateversion" = > 0 ,
"buffers" = > 0 ,
"passwordfile" = > 0 ,
"bannedports" = > '' ,
"maxportallowed" = > 0 ,
"outputfile" = > 0 ,
"noprocess" = > 0 ,
"dbstat" = > 0 ,
"nodbstat" = > 0 ,
"server-log" = > '' ,
"tbstat" = > 0 ,
"notbstat" = > 0 ,
"colstat" = > 0 ,
"nocolstat" = > 0 ,
"idxstat" = > 0 ,
"noidxstat" = > 0 ,
2023-07-06 05:22:05 +00:00
"nomyisamstat" = > 0 ,
"nostructstat" = > 0 ,
2022-12-29 04:13:02 +00:00
"sysstat" = > 0 ,
"nosysstat" = > 0 ,
"pfstat" = > 0 ,
"nopfstat" = > 0 ,
"skippassword" = > 0 ,
"noask" = > 0 ,
"template" = > 0 ,
"json" = > 0 ,
"prettyjson" = > 0 ,
"reportfile" = > 0 ,
"verbose" = > 0 ,
"defaults-file" = > '' ,
"defaults-extra-file" = > '' ,
"protocol" = > '' ,
2023-02-28 13:34:14 +00:00
"dumpdir" = > '' ,
2023-06-22 13:15:25 +00:00
"feature" = > '' ,
"dbgpattern" = > '' ,
"defaultarch" = > 64
2015-08-19 12:45:24 +00:00
) ;
2015-06-18 20:02:55 +00:00
2008-09-08 01:16:39 +00:00
# Gather the options from the command line
2017-06-15 18:52:14 +00:00
GetOptions (
2023-03-11 06:48:00 +00:00
\ % opt , 'nobad' ,
'nogood' , 'noinfo' ,
'debug' , 'nocolor' ,
'forcemem=i' , 'forceswap=i' ,
'host=s' , 'socket=s' ,
'port=i' , 'user=s' ,
'pass=s' , 'skipsize' ,
'checkversion' , 'mysqladmin=s' ,
'mysqlcmd=s' , 'help' ,
'buffers' , 'skippassword' ,
'passwordfile=s' , 'outputfile=s' ,
'silent' , 'noask' ,
'json' , 'prettyjson' ,
'template=s' , 'reportfile=s' ,
'cvefile=s' , 'bannedports=s' ,
'updateversion' , 'maxportallowed=s' ,
'verbose' , 'password=s' ,
'passenv=s' , 'userenv=s' ,
'defaults-file=s' , 'ssl-ca=s' ,
'color' , 'noprocess' ,
'dbstat' , 'nodbstat' ,
'tbstat' , 'notbstat' ,
'colstat' , 'nocolstat' ,
'sysstat' , 'nosysstat' ,
'pfstat' , 'nopfstat' ,
'idxstat' , 'noidxstat' ,
2023-07-06 05:22:05 +00:00
'structstat' , 'nostructstat' ,
'myisamstat' , 'nomyisamstat' ,
2023-03-11 06:48:00 +00:00
'server-log=s' , 'protocol=s' ,
2023-02-28 13:34:14 +00:00
'defaults-extra-file=s' , 'dumpdir=s' ,
2023-06-22 13:15:25 +00:00
'feature=s' , 'dbgpattern=s' ,
'defaultarch=i'
2017-07-05 09:51:33 +00:00
)
or pod2usage (
- exitval = > 1 ,
- verbose = > 99 ,
- sections = > [
"NAME" ,
"IMPORTANT USAGE GUIDELINES" ,
2018-02-18 04:41:14 +00:00
"CONNECTION AND AUTHENTICATION" ,
2017-07-05 09:51:33 +00:00
"PERFORMANCE AND REPORTING OPTIONS" ,
"OUTPUT OPTIONS"
]
) ;
2015-08-19 12:45:24 +00:00
2017-06-15 18:52:14 +00:00
if ( defined $ opt { 'help' } && $ opt { 'help' } == 1 ) {
2017-07-05 09:51:33 +00:00
pod2usage (
- exitval = > 0 ,
- verbose = > 99 ,
- sections = > [
"NAME" ,
"IMPORTANT USAGE GUIDELINES" ,
2018-02-18 04:41:14 +00:00
"CONNECTION AND AUTHENTICATION" ,
2017-07-05 09:51:33 +00:00
"PERFORMANCE AND REPORTING OPTIONS" ,
"OUTPUT OPTIONS"
]
) ;
2008-09-08 01:16:39 +00:00
}
2011-04-02 12:03:32 +00:00
my $ devnull = File::Spec - > devnull ( ) ;
2015-08-19 12:45:24 +00:00
my $ basic_password_files =
( $ opt { passwordfile } eq "0" )
? abs_path ( dirname ( __FILE__ ) ) . "/basic_passwords.txt"
: abs_path ( $ opt { passwordfile } ) ;
2015-06-15 07:47:24 +00:00
2016-11-16 09:05:33 +00:00
# Username from envvar
2017-02-07 05:56:17 +00:00
if ( exists $ opt { userenv } && exists $ ENV { $ opt { userenv } } ) {
2016-11-16 09:05:33 +00:00
$ opt { user } = $ ENV { $ opt { userenv } } ;
}
2016-08-30 11:34:52 +00:00
# Related to password option
2017-02-07 05:56:17 +00:00
if ( exists $ opt { passenv } && exists $ ENV { $ opt { passenv } } ) {
2016-11-16 09:05:33 +00:00
$ opt { pass } = $ ENV { $ opt { passenv } } ;
}
2016-08-31 08:30:20 +00:00
$ opt { pass } = $ opt { password } if ( $ opt { pass } eq 0 and $ opt { password } ne 0 ) ;
2016-08-30 11:34:52 +00:00
2023-03-11 06:48:00 +00:00
if ( $ opt { dumpdir } ne '' ) {
2023-02-28 13:34:14 +00:00
$ opt { dumpdir } = abs_path ( $ opt { dumpdir } ) ;
2023-03-11 06:48:00 +00:00
if ( ! - d $ opt { dumpdir } ) {
2023-02-28 13:34:14 +00:00
mkdir $ opt { dumpdir } or die "Cannot create directory $opt{dumpdir}: $!" ;
2023-03-01 10:16:44 +00:00
}
2023-02-28 13:34:14 +00:00
}
2023-03-11 06:48:00 +00:00
2015-06-18 21:40:12 +00:00
# for RPM distributions
2015-08-19 12:45:24 +00:00
$ basic_password_files = "/usr/share/mysqltuner/basic_passwords.txt"
unless - f "$basic_password_files" ;
2015-06-18 21:40:12 +00:00
2023-07-06 06:19:29 +00:00
$ opt { dbgpattern } = '.*' if ( $ opt { dbgpattern } eq '' ) ;
2016-03-24 22:58:48 +00:00
# check if we need to enable verbose mode
2023-06-07 16:22:02 +00:00
if ( $ opt { feature } ne '' ) { $ opt { verbose } = 1 ; }
2016-03-29 12:22:45 +00:00
if ( $ opt { verbose } ) {
2022-06-15 12:43:18 +00:00
$ opt { checkversion } = 1 ; # Check for updates to MySQLTuner
$ opt { dbstat } = 1 ; # Print database information
$ opt { tbstat } = 1 ; # Print database information
$ opt { idxstat } = 1 ; # Print index information
$ opt { sysstat } = 1 ; # Print index information
$ opt { buffers } = 1 ; # Print global and per-thread buffer values
$ opt { pfstat } = 1 ; # Print performance schema info.
2023-07-06 06:19:29 +00:00
$ opt { structstat } = 1 ; # Print table structure information
$ opt { myisamstat } = 1 ; # Print MyISAM table information
2023-07-06 05:22:05 +00:00
2016-03-29 12:22:45 +00:00
$ opt { cvefile } = 'vulnerabilities.csv' ; #CVE File for vulnerability checks
2016-03-24 22:58:48 +00:00
}
2018-11-26 12:57:11 +00:00
$ opt { nocolor } = 1 if defined ( $ opt { outputfile } ) ;
2022-09-13 13:17:39 +00:00
$ opt { tbstat } = 0 if ( $ opt { notbstat } == 1 ) ; # Don't print table information
$ opt { colstat } = 0 if ( $ opt { nocolstat } == 1 ) ; # Don't print column information
2023-03-22 15:34:10 +00:00
$ opt { dbstat } = 0 if ( $ opt { nodbstat } == 1 ) ; # Don't print database information
2018-11-26 12:57:11 +00:00
$ opt { noprocess } = 0
2022-09-13 13:17:39 +00:00
if ( $ opt { noprocess } == 1 ) ; # Don't print process information
$ opt { sysstat } = 0 if ( $ opt { nosysstat } == 1 ) ; # Don't print sysstat information
2021-08-25 10:01:28 +00:00
$ opt { pfstat } = 0
2022-09-13 13:17:39 +00:00
if ( $ opt { nopfstat } == 1 ) ; # Don't print performance schema information
$ opt { idxstat } = 0 if ( $ opt { noidxstat } == 1 ) ; # Don't print index information
2023-07-06 06:19:29 +00:00
$ opt { structstat } = 0
2023-08-16 05:38:34 +00:00
if ( not defined ( $ opt { structstat } ) or $ opt { nostructstat } == 1 )
; # Don't print table struct information
2023-07-07 07:13:46 +00:00
$ opt { myisamstat } = 1
2023-09-26 20:50:57 +00:00
if ( not defined ( $ opt { myisamstat } ) ) ;
$ opt { myisamstat } = 0 if ( $ opt { nomyisamstat } == 1 ) ; # Don't print MyISAM table information
2023-08-16 05:38:34 +00:00
2016-01-06 00:17:05 +00:00
# for RPM distributions
2016-08-31 08:30:20 +00:00
$ opt { cvefile } = "/usr/share/mysqltuner/vulnerabilities.csv"
unless ( defined $ opt { cvefile } and - f "$opt{cvefile}" ) ;
2016-03-29 12:22:45 +00:00
$ opt { cvefile } = '' unless - f "$opt{cvefile}" ;
$ opt { cvefile } = './vulnerabilities.csv' if - f './vulnerabilities.csv' ;
2016-01-06 00:17:05 +00:00
2016-03-29 12:22:45 +00:00
$ opt { 'bannedports' } = '' unless defined ( $ opt { 'bannedports' } ) ;
my @ banned_ports = split ',' , $ opt { 'bannedports' } ;
2016-01-06 00:17:05 +00:00
2015-08-19 12:45:24 +00:00
#
2015-08-26 13:23:19 +00:00
my $ outputfile = undef ;
$ outputfile = abs_path ( $ opt { outputfile } ) unless $ opt { outputfile } eq "0" ;
2015-06-16 21:38:17 +00:00
2015-08-19 12:45:24 +00:00
my $ fh = undef ;
2015-08-26 13:23:19 +00:00
open ( $ fh , '>' , $ outputfile )
or die ( "Fail opening $outputfile" )
if defined ( $ outputfile ) ;
$ opt { nocolor } = 1 if defined ( $ outputfile ) ;
2018-03-19 16:17:11 +00:00
$ opt { nocolor } = 1 unless ( - t STDOUT ) ;
$ opt { nocolor } = 0 if ( $ opt { color } == 1 ) ;
2018-02-23 11:34:32 +00:00
2016-04-11 10:01:01 +00:00
# Setting up the colors for the print styles
2016-04-19 14:19:31 +00:00
my $ me = `whoami` ;
$ me =~ s/\n//g ;
my $ good = ( $ opt { nocolor } == 0 ) ? "[\e[0;32mOK\e[0m]" : "[OK]" ;
my $ bad = ( $ opt { nocolor } == 0 ) ? "[\e[0;31m!!\e[0m]" : "[!!]" ;
my $ info = ( $ opt { nocolor } == 0 ) ? "[\e[0;34m--\e[0m]" : "[--]" ;
my $ deb = ( $ opt { nocolor } == 0 ) ? "[\e[0;31mDG\e[0m]" : "[DG]" ;
my $ cmd = ( $ opt { nocolor } == 0 ) ? "\e[1;32m[CMD]($me)" : "[CMD]($me)" ;
my $ end = ( $ opt { nocolor } == 0 ) ? "\e[0m" : "" ;
2008-09-08 01:16:39 +00:00
2021-01-30 01:31:00 +00:00
# Maximum lines of log output to read from end
my $ maxlines = 30000 ;
2016-08-26 08:40:58 +00:00
# Checks for supported or EOL'ed MySQL versions
my ( $ mysqlvermajor , $ mysqlverminor , $ mysqlvermicro ) ;
2021-01-28 07:44:14 +00:00
# Database
my @ dblist ;
2015-12-10 10:52:39 +00:00
# Super structure containing all information
2015-07-16 15:14:42 +00:00
my % result ;
2022-06-23 12:31:46 +00:00
$ result { 'MySQLTuner' } { 'version' } = $ tunerversion ;
$ result { 'MySQLTuner' } { 'datetime' } = `date '+%d-%m-%Y %H:%M:%S'` ;
$ result { 'MySQLTuner' } { 'options' } = \ % opt ;
2016-08-31 08:30:20 +00:00
2008-09-08 01:16:39 +00:00
# Functions that handle the print styles
2015-06-16 21:38:17 +00:00
sub prettyprint {
2016-03-29 12:22:45 +00:00
print $ _ [ 0 ] . "\n" unless ( $ opt { 'silent' } or $ opt { 'json' } ) ;
2015-08-19 12:45:24 +00:00
print $ fh $ _ [ 0 ] . "\n" if defined ( $ fh ) ;
}
2023-06-07 17:29:41 +00:00
sub goodprint {
prettyprint $ good . " " . $ _ [ 0 ] unless ( $ opt { nogood } == 1 ) ;
2023-06-07 16:22:02 +00:00
}
2023-06-07 17:29:41 +00:00
sub infoprint {
prettyprint $ info . " " . $ _ [ 0 ] unless ( $ opt { noinfo } == 1 ) ;
2023-06-07 16:22:02 +00:00
}
2023-06-07 17:29:41 +00:00
sub badprint {
prettyprint $ bad . " " . $ _ [ 0 ] unless ( $ opt { nobad } == 1 ) ;
2023-06-07 16:22:02 +00:00
}
2023-06-07 17:29:41 +00:00
2023-06-07 16:22:02 +00:00
sub debugprint {
2023-06-07 17:29:41 +00:00
prettyprint $ deb . " " . $ _ [ 0 ] unless ( $ opt { debug } == 0 ) ;
2023-06-07 16:22:02 +00:00
}
2016-03-29 12:22:45 +00:00
2015-08-19 12:45:24 +00:00
sub redwrap {
return ( $ opt { nocolor } == 0 ) ? "\e[0;31m" . $ _ [ 0 ] . "\e[0m" : $ _ [ 0 ] ;
}
sub greenwrap {
return ( $ opt { nocolor } == 0 ) ? "\e[0;32m" . $ _ [ 0 ] . "\e[0m" : $ _ [ 0 ] ;
2015-06-16 21:38:17 +00:00
}
2023-06-07 17:29:41 +00:00
2023-06-07 16:22:02 +00:00
sub cmdprint {
2023-06-07 17:29:41 +00:00
prettyprint $ cmd . " " . $ _ [ 0 ] . $ end ;
2023-06-07 16:22:02 +00:00
}
2016-04-19 14:19:31 +00:00
sub infoprintml {
2023-06-07 17:29:41 +00:00
for my $ ln ( @ _ ) { $ ln =~ s/\n//g ; infoprint "\t$ln" ; }
2016-04-19 14:19:31 +00:00
}
sub infoprintcmd {
cmdprint "@_" ;
infoprintml grep { $ _ ne '' and $ _ !~ /^\s*$/ } `@_ 2>&1` ;
}
2016-04-11 10:01:01 +00:00
sub subheaderprint {
2016-04-19 14:19:31 +00:00
my $ tln = 100 ;
my $ sln = 8 ;
my $ ln = length ( "@_" ) + 2 ;
2016-04-11 10:01:01 +00:00
2016-04-19 14:19:31 +00:00
prettyprint " " ;
prettyprint "-" x $ sln . " @_ " . "-" x ( $ tln - $ ln - $ sln ) ;
2016-04-11 10:01:01 +00:00
}
2016-04-19 14:19:31 +00:00
2016-04-11 10:01:01 +00:00
sub infoprinthcmd {
2016-04-19 14:19:31 +00:00
subheaderprint "$_[0]" ;
infoprintcmd "$_[1]" ;
2016-04-11 10:01:01 +00:00
}
2008-09-08 01:16:39 +00:00
2023-06-07 16:22:02 +00:00
sub is_remote () {
my $ host = $ opt { 'host' } ;
return 0 if ( $ host eq '' ) ;
return 0 if ( $ host eq 'localhost' ) ;
return 0 if ( $ host eq '127.0.0.1' ) ;
return 1 ;
}
2023-07-06 06:19:29 +00:00
sub is_int {
2023-06-18 19:52:36 +00:00
return 0 unless defined $ _ [ 0 ] ;
2023-07-06 06:19:29 +00:00
my $ str = $ _ [ 0 ] ;
2023-06-18 19:52:36 +00:00
#trim whitespace both sides
$ str =~ s/^\s+|\s+$//g ;
2023-06-07 17:29:41 +00:00
2023-06-18 19:52:36 +00:00
#Alternatively, to match any float-like numeric, use:
# m/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/
#flatten to string and match dash or plus and one or more digits
2023-07-06 06:19:29 +00:00
if ( $ str =~ /^(\-|\+)?\d+?$/ ) {
2023-06-18 19:52:36 +00:00
return 1 ;
}
return 0 ;
}
2023-07-06 06:19:29 +00:00
2018-05-21 23:10:22 +00:00
# Calculates the number of physical cores considering HyperThreading
2017-03-13 16:22:05 +00:00
sub cpu_cores {
2021-07-02 16:31:21 +00:00
if ( $^O eq 'linux' ) {
my $ cntCPU =
`awk -F: '/^core id/ && !P[\$2] { CORES++; P[\$2]=1 }; /^physical id/ && !N[\$2] { CPUs++; N[\$2]=1 }; END { print CPUs*CORES }' /proc/cpuinfo` ;
2021-10-16 15:07:14 +00:00
chomp $ cntCPU ;
2021-07-02 16:31:21 +00:00
return ( $ cntCPU == 0 ? `nproc` : $ cntCPU ) ;
}
2021-07-02 14:55:43 +00:00
2021-07-02 16:31:21 +00:00
if ( $^O eq 'freebsd' ) {
my $ cntCPU = `sysctl -n kern.smp.cores` ;
chomp $ cntCPU ;
return $ cntCPU + 0 ;
2021-07-02 14:55:43 +00:00
}
return 0 ;
2017-03-13 16:22:05 +00:00
}
2015-12-10 10:52:39 +00:00
# Calculates the parameter passed in bytes, then rounds it to one decimal place
2008-09-08 01:16:39 +00:00
sub hr_bytes {
2015-08-19 12:45:24 +00:00
my $ num = shift ;
2017-02-07 05:56:17 +00:00
return "0B" unless defined ( $ num ) ;
return "0B" if $ num eq "NULL" ;
2023-02-10 06:22:14 +00:00
return "0B" if $ num eq "" ;
2017-02-07 05:56:17 +00:00
2022-12-29 04:13:02 +00:00
if ( $ num >= ( 1024 ** 3 ) ) { # GB
2015-08-19 12:45:24 +00:00
return sprintf ( "%.1f" , ( $ num / ( 1024 ** 3 ) ) ) . "G" ;
}
2022-09-13 13:17:39 +00:00
elsif ( $ num >= ( 1024 ** 2 ) ) { # MB
2015-08-19 12:45:24 +00:00
return sprintf ( "%.1f" , ( $ num / ( 1024 ** 2 ) ) ) . "M" ;
}
2022-09-13 13:17:39 +00:00
elsif ( $ num >= 1024 ) { # KB
2015-08-19 12:45:24 +00:00
return sprintf ( "%.1f" , ( $ num / 1024 ) ) . "K" ;
}
else {
return $ num . "B" ;
}
2008-09-08 01:16:39 +00:00
}
2017-01-23 16:32:47 +00:00
sub hr_raw {
my $ num = shift ;
2017-02-07 05:56:17 +00:00
return "0" unless defined ( $ num ) ;
return "0" if $ num eq "NULL" ;
if ( $ num =~ /^(\d+)G$/ ) {
return $ 1 * 1024 * 1024 * 1024 ;
2017-01-23 16:32:47 +00:00
}
2017-02-07 05:56:17 +00:00
if ( $ num =~ /^(\d+)M$/ ) {
return $ 1 * 1024 * 1024 ;
2017-01-23 16:32:47 +00:00
}
2017-02-07 05:56:17 +00:00
if ( $ num =~ /^(\d+)K$/ ) {
return $ 1 * 1024 ;
2017-01-23 16:32:47 +00:00
}
2017-02-07 05:56:17 +00:00
if ( $ num =~ /^(\d+)$/ ) {
return $ 1 ;
2017-01-23 16:32:47 +00:00
}
return $ num ;
}
2015-12-10 10:52:39 +00:00
# Calculates the parameter passed in bytes, then rounds it to the nearest integer
2008-09-08 01:16:39 +00:00
sub hr_bytes_rnd {
2015-08-19 12:45:24 +00:00
my $ num = shift ;
2017-02-07 05:56:17 +00:00
return "0B" unless defined ( $ num ) ;
return "0B" if $ num eq "NULL" ;
2022-12-29 04:13:02 +00:00
if ( $ num >= ( 1024 ** 3 ) ) { # GB
2015-08-19 12:45:24 +00:00
return int ( ( $ num / ( 1024 ** 3 ) ) ) . "G" ;
}
2022-09-13 13:17:39 +00:00
elsif ( $ num >= ( 1024 ** 2 ) ) { # MB
2015-08-19 12:45:24 +00:00
return int ( ( $ num / ( 1024 ** 2 ) ) ) . "M" ;
}
2022-09-13 13:17:39 +00:00
elsif ( $ num >= 1024 ) { # KB
2015-08-19 12:45:24 +00:00
return int ( ( $ num / 1024 ) ) . "K" ;
}
else {
return $ num . "B" ;
}
2008-09-08 01:16:39 +00:00
}
# Calculates the parameter passed to the nearest power of 1000, then rounds it to the nearest integer
sub hr_num {
2015-08-19 12:45:24 +00:00
my $ num = shift ;
if ( $ num >= ( 1000 ** 3 ) ) { # Billions
return int ( ( $ num / ( 1000 ** 3 ) ) ) . "B" ;
}
elsif ( $ num >= ( 1000 ** 2 ) ) { # Millions
return int ( ( $ num / ( 1000 ** 2 ) ) ) . "M" ;
}
elsif ( $ num >= 1000 ) { # Thousands
return int ( ( $ num / 1000 ) ) . "K" ;
}
else {
return $ num ;
}
2008-09-08 01:16:39 +00:00
}
2015-06-18 20:02:55 +00:00
# Calculate Percentage
2015-08-19 12:45:24 +00:00
sub percentage {
my $ value = shift ;
my $ total = shift ;
$ total = 0 unless defined $ total ;
2016-11-28 19:39:47 +00:00
$ total = 0 if $ total eq "NULL" ;
2015-08-19 12:45:24 +00:00
return 100 , 00 if $ total == 0 ;
return sprintf ( "%.2f" , ( $ value * 100 / $ total ) ) ;
2015-06-18 20:02:55 +00:00
}
2022-09-13 13:17:39 +00:00
# Calculates uptime to display in a human-readable form
2008-09-08 01:16:39 +00:00
sub pretty_uptime {
2015-08-19 12:45:24 +00:00
my $ uptime = shift ;
my $ seconds = $ uptime % 60 ;
my $ minutes = int ( ( $ uptime % 3600 ) / 60 ) ;
my $ hours = int ( ( $ uptime % 86400 ) / ( 3600 ) ) ;
my $ days = int ( $ uptime / ( 86400 ) ) ;
my $ uptimestring ;
if ( $ days > 0 ) {
$ uptimestring = "${days}d ${hours}h ${minutes}m ${seconds}s" ;
}
elsif ( $ hours > 0 ) {
$ uptimestring = "${hours}h ${minutes}m ${seconds}s" ;
}
elsif ( $ minutes > 0 ) {
$ uptimestring = "${minutes}m ${seconds}s" ;
}
else {
$ uptimestring = "${seconds}s" ;
}
return $ uptimestring ;
2008-09-08 01:16:39 +00:00
}
# Retrieves the memory installed on this machine
2021-01-27 04:09:41 +00:00
my ( $ physical_memory , $ swap_memory , $ duflags , $ xargsflags ) ;
2015-08-19 12:45:24 +00:00
2016-08-30 11:16:33 +00:00
sub memerror {
2016-08-31 08:30:20 +00:00
badprint
"Unable to determine total memory/swap; use '--forcemem' and '--forceswap'" ;
2016-08-30 11:16:33 +00:00
exit 1 ;
}
2016-03-29 12:22:45 +00:00
2016-08-30 11:16:33 +00:00
sub os_setup {
2015-08-19 12:45:24 +00:00
my $ os = `uname` ;
2021-02-05 14:25:09 +00:00
$ duflags = ( $ os =~ /Linux/ ) ? '-b' : '' ;
$ xargsflags = ( $ os =~ /Darwin|SunOS/ ) ? '' : '-r' ;
2015-08-19 12:45:24 +00:00
if ( $ opt { 'forcemem' } > 0 ) {
$ physical_memory = $ opt { 'forcemem' } * 1048576 ;
infoprint "Assuming $opt{'forcemem'} MB of physical memory" ;
if ( $ opt { 'forceswap' } > 0 ) {
$ swap_memory = $ opt { 'forceswap' } * 1048576 ;
infoprint "Assuming $opt{'forceswap'} MB of swap space" ;
}
else {
$ swap_memory = 0 ;
2016-03-29 12:22:45 +00:00
badprint "Assuming 0 MB of swap space (use --forceswap to specify)" ;
2015-08-19 12:45:24 +00:00
}
}
else {
2015-11-10 11:48:25 +00:00
if ( $ os =~ /Linux|CYGWIN/ ) {
2015-08-19 12:45:24 +00:00
$ physical_memory =
`grep -i memtotal: /proc/meminfo | awk '{print \$2}'`
or memerror ;
$ physical_memory *= 1024 ;
$ swap_memory =
`grep -i swaptotal: /proc/meminfo | awk '{print \$2}'`
or memerror ;
$ swap_memory *= 1024 ;
}
elsif ( $ os =~ /Darwin/ ) {
$ physical_memory = `sysctl -n hw.memsize` or memerror ;
$ swap_memory =
`sysctl -n vm.swapusage | awk '{print \$3}' | sed 's/\..*\$//'`
or memerror ;
}
elsif ( $ os =~ /NetBSD|OpenBSD|FreeBSD/ ) {
$ physical_memory = `sysctl -n hw.physmem` or memerror ;
if ( $ physical_memory < 0 ) {
$ physical_memory = `sysctl -n hw.physmem64` or memerror ;
}
$ swap_memory =
`swapctl -l | grep '^/' | awk '{ s+= \$2 } END { print s }'`
or memerror ;
}
elsif ( $ os =~ /BSD/ ) {
$ physical_memory = `sysctl -n hw.realmem` or memerror ;
$ swap_memory =
`swapinfo | grep '^/' | awk '{ s+= \$2 } END { print s }'` ;
}
elsif ( $ os =~ /SunOS/ ) {
$ physical_memory =
`/usr/sbin/prtconf | grep Memory | cut -f 3 -d ' '`
or memerror ;
chomp ( $ physical_memory ) ;
$ physical_memory = $ physical_memory * 1024 * 1024 ;
}
elsif ( $ os =~ /AIX/ ) {
$ physical_memory =
`lsattr -El sys0 | grep realmem | awk '{print \$2}'`
or memerror ;
chomp ( $ physical_memory ) ;
$ physical_memory = $ physical_memory * 1024 ;
$ swap_memory = `lsps -as | awk -F"(MB| +)" '/MB /{print \$2}'`
or memerror ;
chomp ( $ swap_memory ) ;
$ swap_memory = $ swap_memory * 1024 * 1024 ;
}
2016-03-29 12:22:45 +00:00
elsif ( $ os =~ /windows/i ) {
2016-02-16 15:29:47 +00:00
$ physical_memory =
2016-03-29 12:22:45 +00:00
`wmic ComputerSystem get TotalPhysicalMemory | perl -ne "chomp; print if /[0-9]+/;"`
2016-02-16 15:29:47 +00:00
or memerror ;
2016-03-29 12:22:45 +00:00
$ swap_memory =
`wmic OS get FreeVirtualMemory | perl -ne "chomp; print if /[0-9]+/;"`
2016-02-16 15:29:47 +00:00
or memerror ;
}
2015-08-19 12:45:24 +00:00
}
debugprint "Physical Memory: $physical_memory" ;
debugprint "Swap Memory: $swap_memory" ;
chomp ( $ physical_memory ) ;
chomp ( $ swap_memory ) ;
chomp ( $ os ) ;
$ result { 'OS' } { 'OS Type' } = $ os ;
$ result { 'OS' } { 'Physical Memory' } { 'bytes' } = $ physical_memory ;
$ result { 'OS' } { 'Physical Memory' } { 'pretty' } = hr_bytes ( $ physical_memory ) ;
$ result { 'OS' } { 'Swap Memory' } { 'bytes' } = $ swap_memory ;
$ result { 'OS' } { 'Swap Memory' } { 'pretty' } = hr_bytes ( $ swap_memory ) ;
2016-08-31 08:30:20 +00:00
$ result { 'OS' } { 'Other Processes' } { 'bytes' } = get_other_process_memory ( ) ;
$ result { 'OS' } { 'Other Processes' } { 'pretty' } =
hr_bytes ( get_other_process_memory ( ) ) ;
2008-09-08 01:16:39 +00:00
}
2016-04-05 13:49:43 +00:00
sub get_http_cli {
2016-04-19 14:19:31 +00:00
my $ httpcli = which ( "curl" , $ ENV { 'PATH' } ) ;
2016-04-05 13:49:43 +00:00
chomp ( $ httpcli ) ;
2016-04-18 14:45:34 +00:00
if ( $ httpcli ) {
2016-04-19 14:19:31 +00:00
return $ httpcli ;
2016-04-05 13:49:43 +00:00
}
2016-04-19 14:19:31 +00:00
$ httpcli = which ( "wget" , $ ENV { 'PATH' } ) ;
2016-04-05 13:49:43 +00:00
chomp ( $ httpcli ) ;
2016-04-18 14:45:34 +00:00
if ( $ httpcli ) {
2016-04-19 14:19:31 +00:00
return $ httpcli ;
2016-04-05 13:49:43 +00:00
}
return "" ;
}
2016-04-18 14:45:34 +00:00
2015-08-25 14:15:54 +00:00
# Checks for updates to MySQLTuner
sub validate_tuner_version {
2019-10-03 20:33:22 +00:00
if ( $ opt { 'checkversion' } eq 0 ) {
2016-03-29 12:22:45 +00:00
print "\n" unless ( $ opt { 'silent' } or $ opt { 'json' } ) ;
infoprint "Skipped version check for MySQLTuner script" ;
return ;
}
2015-11-23 07:08:25 +00:00
2016-03-29 12:22:45 +00:00
my $ update ;
2017-07-05 09:51:33 +00:00
my $ url =
"https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl" ;
2016-04-18 14:45:34 +00:00
my $ httpcli = get_http_cli ( ) ;
if ( $ httpcli =~ /curl$/ ) {
2016-03-29 12:22:45 +00:00
debugprint "$httpcli is available." ;
2015-11-23 07:08:25 +00:00
2016-03-29 12:22:45 +00:00
debugprint
2017-04-20 22:13:45 +00:00
"$httpcli -m 3 -silent '$url' 2>/dev/null | grep 'my \$tunerversion'| cut -d\\\" -f2" ;
2016-03-29 12:22:45 +00:00
$ update =
2017-04-20 22:13:45 +00:00
`$httpcli -m 3 -silent '$url' 2>/dev/null | grep 'my \$tunerversion'| cut -d\\\" -f2` ;
2016-03-29 12:22:45 +00:00
chomp ( $ update ) ;
debugprint "VERSION: $update" ;
2015-11-23 07:08:25 +00:00
2016-03-29 12:22:45 +00:00
compare_tuner_version ( $ update ) ;
return ;
2016-04-19 14:19:31 +00:00
}
2015-11-23 07:08:25 +00:00
2016-04-19 14:19:31 +00:00
if ( $ httpcli =~ /wget$/ ) {
2016-03-29 12:22:45 +00:00
debugprint "$httpcli is available." ;
2015-11-23 07:08:25 +00:00
2016-03-29 12:22:45 +00:00
debugprint
2017-04-20 22:13:45 +00:00
"$httpcli -e timestamping=off -t 1 -T 3 -O - '$url' 2>$devnull| grep 'my \$tunerversion'| cut -d\\\" -f2" ;
2016-03-29 12:22:45 +00:00
$ update =
2017-04-20 22:13:45 +00:00
`$httpcli -e timestamping=off -t 1 -T 3 -O - '$url' 2>$devnull| grep 'my \$tunerversion'| cut -d\\\" -f2` ;
2016-03-29 12:22:45 +00:00
chomp ( $ update ) ;
compare_tuner_version ( $ update ) ;
return ;
}
debugprint "curl and wget are not available." ;
infoprint "Unable to check for the latest MySQLTuner version" ;
2017-02-07 05:56:17 +00:00
infoprint
2022-09-13 13:17:39 +00:00
"Using --pass and --password option is insecure during MySQLTuner execution (password disclosure)"
2017-02-07 05:56:17 +00:00
if ( defined ( $ opt { 'pass' } ) ) ;
2016-02-20 16:07:19 +00:00
}
2015-08-25 14:15:54 +00:00
2016-03-24 22:58:48 +00:00
# Checks for updates to MySQLTuner
sub update_tuner_version {
2016-03-29 12:22:45 +00:00
if ( $ opt { 'updateversion' } eq 0 ) {
badprint "Skipped version update for MySQLTuner script" ;
print "\n" unless ( $ opt { 'silent' } or $ opt { 'json' } ) ;
return ;
}
2016-02-20 16:05:33 +00:00
2016-03-29 12:22:45 +00:00
my $ update ;
2022-06-23 12:31:46 +00:00
my $ fullpath = "" ;
2016-03-29 12:22:45 +00:00
my $ url = "https://raw.githubusercontent.com/major/MySQLTuner-perl/master/" ;
my @ scripts =
( "mysqltuner.pl" , "basic_passwords.txt" , "vulnerabilities.csv" ) ;
my $ totalScripts = scalar ( @ scripts ) ;
my $ receivedScripts = 0 ;
2016-04-18 14:45:34 +00:00
my $ httpcli = get_http_cli ( ) ;
2016-03-29 12:22:45 +00:00
foreach my $ script ( @ scripts ) {
2016-03-24 22:58:48 +00:00
2016-04-18 14:45:34 +00:00
if ( $ httpcli =~ /curl$/ ) {
2016-03-29 12:22:45 +00:00
debugprint "$httpcli is available." ;
2022-06-23 12:31:46 +00:00
$ fullpath = dirname ( __FILE__ ) . "/" . $ script ;
2022-03-28 21:03:57 +00:00
debugprint "FullPath: $fullpath" ;
2016-03-29 12:22:45 +00:00
debugprint
2022-06-23 12:31:46 +00:00
"$httpcli --connect-timeout 3 '$url$script' 2>$devnull > $fullpath" ;
2016-03-29 12:22:45 +00:00
$ update =
2022-06-23 12:31:46 +00:00
`$httpcli --connect-timeout 3 '$url$script' 2>$devnull > $fullpath` ;
2016-03-29 12:22:45 +00:00
chomp ( $ update ) ;
debugprint "$script updated: $update" ;
if ( - s $ script eq 0 ) {
badprint "Couldn't update $script" ;
}
else {
+ + $ receivedScripts ;
debugprint "$script updated: $update" ;
}
2016-03-24 22:58:48 +00:00
}
2016-04-18 14:45:34 +00:00
elsif ( $ httpcli =~ /wget$/ ) {
2016-03-29 12:22:45 +00:00
2016-04-19 14:19:31 +00:00
debugprint "$httpcli is available." ;
debugprint
2017-07-05 09:51:33 +00:00
"$httpcli -qe timestamping=off -t 1 -T 3 -O $script '$url$script'" ;
2016-04-19 14:19:31 +00:00
$ update =
2017-07-05 09:51:33 +00:00
`$httpcli -qe timestamping=off -t 1 -T 3 -O $script '$url$script'` ;
2016-04-19 14:19:31 +00:00
chomp ( $ update ) ;
if ( - s $ script eq 0 ) {
badprint "Couldn't update $script" ;
}
else {
+ + $ receivedScripts ;
debugprint "$script updated: $update" ;
}
}
else {
debugprint "curl and wget are not available." ;
infoprint "Unable to check for the latest MySQLTuner version" ;
}
2016-03-24 22:58:48 +00:00
}
2016-03-29 12:22:45 +00:00
if ( $ receivedScripts eq $ totalScripts ) {
goodprint "Successfully updated MySQLTuner script" ;
}
else {
badprint "Couldn't update MySQLTuner script" ;
2016-03-24 22:58:48 +00:00
}
2022-06-30 12:46:54 +00:00
infoprint "Stopping program: MySQLTuner script must be updated first." ;
2019-10-03 20:33:22 +00:00
exit 0 ;
2016-02-20 16:07:19 +00:00
}
sub compare_tuner_version {
2016-03-29 12:22:45 +00:00
my $ remoteversion = shift ;
debugprint "Remote data: $remoteversion" ;
#exit 0;
if ( $ remoteversion ne $ tunerversion ) {
badprint
2022-06-30 12:46:54 +00:00
"There is a new version of MySQLTuner available ($remoteversion)" ;
2016-03-29 12:22:45 +00:00
update_tuner_version ( ) ;
return ;
}
2022-06-30 12:46:54 +00:00
goodprint "You have the latest version of MySQLTuner ($tunerversion)" ;
2016-07-13 10:58:30 +00:00
return ;
2015-08-25 14:15:54 +00:00
}
2008-09-08 01:16:39 +00:00
# Checks to see if a MySQL login is possible
2015-08-19 12:45:24 +00:00
my ( $ mysqllogin , $ doremote , $ remotestring , $ mysqlcmd , $ mysqladmincmd ) ;
2015-11-12 22:55:14 +00:00
my $ osname = $^O ;
2016-03-29 12:22:45 +00:00
if ( $ osname eq 'MSWin32' ) {
eval { require Win32 ; } or last ;
$ osname = Win32:: GetOSName ( ) ;
2022-06-30 12:46:54 +00:00
infoprint "* Windows OS ($osname) is not fully supported.\n" ;
2016-03-29 12:22:45 +00:00
#exit 1;
2015-11-12 22:55:14 +00:00
}
2016-03-29 12:22:45 +00:00
2008-09-08 01:16:39 +00:00
sub mysql_setup {
2015-08-19 12:45:24 +00:00
$ doremote = 0 ;
$ remotestring = '' ;
if ( $ opt { mysqladmin } ) {
$ mysqladmincmd = $ opt { mysqladmin } ;
}
else {
2016-04-19 14:19:31 +00:00
$ mysqladmincmd = which ( "mysqladmin" , $ ENV { 'PATH' } ) ;
2021-01-27 06:25:30 +00:00
if ( ! - e $ mysqladmincmd ) {
$ mysqladmincmd = which ( "mariadb-admin" , $ ENV { 'PATH' } ) ;
2021-02-05 14:25:09 +00:00
}
2015-08-19 12:45:24 +00:00
}
chomp ( $ mysqladmincmd ) ;
if ( ! - e $ mysqladmincmd && $ opt { mysqladmin } ) {
badprint "Unable to find the mysqladmin command you specified: "
. $ mysqladmincmd . "" ;
2015-08-24 08:00:10 +00:00
exit 1 ;
2015-08-19 12:45:24 +00:00
}
elsif ( ! - e $ mysqladmincmd ) {
2021-02-05 14:25:09 +00:00
badprint
"Couldn't find mysqladmin/mariadb-admin in your \$PATH. Is MySQL installed?" ;
2023-07-06 06:19:29 +00:00
2023-06-17 15:38:18 +00:00
#exit 1;
2015-08-19 12:45:24 +00:00
}
if ( $ opt { mysqlcmd } ) {
$ mysqlcmd = $ opt { mysqlcmd } ;
}
else {
2016-04-19 14:19:31 +00:00
$ mysqlcmd = which ( "mysql" , $ ENV { 'PATH' } ) ;
2021-01-27 06:25:30 +00:00
if ( ! - e $ mysqlcmd ) {
$ mysqlcmd = which ( "mariadb" , $ ENV { 'PATH' } ) ;
2021-02-05 14:25:09 +00:00
}
2015-08-19 12:45:24 +00:00
}
chomp ( $ mysqlcmd ) ;
if ( ! - e $ mysqlcmd && $ opt { mysqlcmd } ) {
badprint "Unable to find the mysql command you specified: "
. $ mysqlcmd . "" ;
2015-08-24 08:00:10 +00:00
exit 1 ;
2015-08-19 12:45:24 +00:00
}
elsif ( ! - e $ mysqlcmd ) {
2021-02-05 14:25:09 +00:00
badprint
"Couldn't find mysql/mariadb in your \$PATH. Is MySQL installed?" ;
2015-08-24 08:00:10 +00:00
exit 1 ;
2015-08-19 12:45:24 +00:00
}
2015-08-24 08:32:56 +00:00
$ mysqlcmd =~ s/\n$//g ;
2016-03-29 12:22:45 +00:00
my $ mysqlclidefaults = `$mysqlcmd --print-defaults` ;
2015-08-25 12:07:13 +00:00
debugprint "MySQL Client: $mysqlclidefaults" ;
2016-03-29 12:22:45 +00:00
if ( $ mysqlclidefaults =~ /auto-vertical-output/ ) {
badprint
"Avoid auto-vertical-output in configuration file(s) for MySQL like" ;
exit 1 ;
2015-08-25 12:07:13 +00:00
}
2015-08-24 08:32:56 +00:00
debugprint "MySQL Client: $mysqlcmd" ;
2015-08-19 12:45:24 +00:00
# Are we being asked to connect via a socket?
if ( $ opt { socket } ne 0 ) {
2023-09-24 22:28:43 +00:00
if ( $ opt { port } ne 0 ) {
$ remotestring = " -S $opt{socket} -P $opt{port}" ;
} else {
$ remotestring = " -S $opt{socket}" ;
}
2015-08-19 12:45:24 +00:00
}
2017-07-05 09:51:33 +00:00
2022-06-23 12:31:46 +00:00
if ( $ opt { protocol } ne '' ) {
2022-02-07 23:31:00 +00:00
$ remotestring = " --protocol=$opt{protocol}" ;
}
2015-08-19 12:45:24 +00:00
# Are we being asked to connect to a remote server?
if ( $ opt { host } ne 0 ) {
chomp ( $ opt { host } ) ;
2023-09-24 22:28:43 +00:00
$ opt { port } = ( $ opt { port } eq 0 ) ? 3306 : $ opt { port } ;
2015-08-19 12:45:24 +00:00
2016-03-29 12:22:45 +00:00
# If we're doing a remote connection, but forcemem wasn't specified, we need to exit
2023-06-07 17:29:41 +00:00
if ( $ opt { 'forcemem' } eq 0 && is_remote eq 1 ) {
2016-03-29 12:22:45 +00:00
badprint "The --forcemem option is required for remote connections" ;
2023-07-06 06:19:29 +00:00
badprint
"Assuming RAM memory is 1Gb for simplify remote connection usage" ;
2023-06-26 07:42:58 +00:00
$ opt { 'forcemem' } = 1024 ;
2023-07-06 06:19:29 +00:00
2023-06-26 07:42:58 +00:00
#exit 1;
}
if ( $ opt { 'forceswap' } eq 0 && is_remote eq 1 ) {
2023-07-06 06:19:29 +00:00
badprint
"The --forceswap option is required for remote connections" ;
badprint
"Assuming Swap size is 1Gb for simplify remote connection usage" ;
2023-06-26 07:42:58 +00:00
$ opt { 'forceswap' } = 1024 ;
2023-07-06 06:19:29 +00:00
2023-06-26 07:42:58 +00:00
#exit 1;
2015-08-19 12:45:24 +00:00
}
infoprint "Performing tests on $opt{host}:$opt{port}" ;
$ remotestring = " -h $opt{host} -P $opt{port}" ;
2023-06-07 17:29:41 +00:00
$ doremote = is_remote ( ) ;
2017-07-05 09:51:33 +00:00
}
else {
$ opt { host } = '127.0.0.1' ;
2015-08-19 12:45:24 +00:00
}
2016-03-29 12:22:45 +00:00
2017-09-15 08:53:57 +00:00
if ( $ opt { 'ssl-ca' } ne 0 ) {
2018-01-10 14:14:19 +00:00
if ( - e - r - f $ opt { 'ssl-ca' } ) {
$ remotestring . = " --ssl-ca=$opt{'ssl-ca'}" ;
infoprint
"Will connect using ssl public key passed on the command line" ;
return 1 ;
}
else {
badprint
"Attempted to use passed ssl public key, but it was not found or could not be read" ;
exit 1 ;
}
2017-09-15 08:53:57 +00:00
}
2023-03-11 06:48:00 +00:00
# Did we already get a username with or without password on the command line?
2023-03-09 11:40:42 +00:00
if ( $ opt { user } ne 0 ) {
2023-03-11 06:48:00 +00:00
$ mysqllogin =
"-u $opt{user} "
. ( ( $ opt { pass } ne 0 ) ? "-p'$opt{pass}' " : " " )
. $ remotestring ;
2023-07-06 06:19:29 +00:00
my $ loginstatus =
`$mysqlcmd -Nrs -e 'select "mysqld is alive";' $mysqllogin 2>&1` ;
2016-03-21 14:51:16 +00:00
if ( $ loginstatus =~ /mysqld is alive/ ) {
2016-03-29 12:22:45 +00:00
goodprint "Logged in using credentials passed on the command line" ;
2016-03-21 14:51:16 +00:00
return 1 ;
}
else {
badprint
"Attempted to use login credentials, but they were invalid" ;
exit 1 ;
}
}
2016-03-29 12:22:45 +00:00
2016-04-19 14:19:31 +00:00
my $ svcprop = which ( "svcprop" , $ ENV { 'PATH' } ) ;
2015-08-19 12:45:24 +00:00
if ( substr ( $ svcprop , 0 , 1 ) =~ "/" ) {
# We are on solaris
( my $ mysql_login =
`svcprop -p quickbackup/username svc:/network/mysql-quickbackup:default`
) =~ s/\s+$// ;
( my $ mysql_pass =
`svcprop -p quickbackup/password svc:/network/mysql-quickbackup:default`
) =~ s/\s+$// ;
if ( substr ( $ mysql_login , 0 , 7 ) ne "svcprop" ) {
# mysql-quickbackup is installed
$ mysqllogin = "-u $mysql_login -p$mysql_pass" ;
my $ loginstatus = `mysqladmin $mysqllogin ping 2>&1` ;
if ( $ loginstatus =~ /mysqld is alive/ ) {
2016-03-29 12:22:45 +00:00
goodprint "Logged in using credentials from mysql-quickbackup." ;
2015-08-19 12:45:24 +00:00
return 1 ;
}
else {
badprint
"Attempted to use login credentials from mysql-quickbackup, but they failed." ;
2015-08-24 08:00:10 +00:00
exit 1 ;
2015-08-19 12:45:24 +00:00
}
}
}
elsif ( - r "/etc/psa/.psa.shadow" and $ doremote == 0 ) {
# It's a Plesk box, use the available credentials
$ mysqllogin = "-u admin -p`cat /etc/psa/.psa.shadow`" ;
my $ loginstatus = `$mysqladmincmd ping $mysqllogin 2>&1` ;
unless ( $ loginstatus =~ /mysqld is alive/ ) {
2016-03-29 12:22:45 +00:00
2016-03-23 15:18:36 +00:00
# Plesk 10+
2016-03-29 12:22:45 +00:00
$ mysqllogin =
"-u admin -p`/usr/local/psa/bin/admin --show-password`" ;
2016-03-23 15:18:36 +00:00
$ loginstatus = `$mysqladmincmd ping $mysqllogin 2>&1` ;
unless ( $ loginstatus =~ /mysqld is alive/ ) {
2016-03-29 12:22:45 +00:00
badprint
"Attempted to use login credentials from Plesk and Plesk 10+, but they failed." ;
exit 1 ;
2016-03-23 15:18:36 +00:00
}
2015-08-19 12:45:24 +00:00
}
}
elsif ( - r "/usr/local/directadmin/conf/mysql.conf" and $ doremote == 0 ) {
# It's a DirectAdmin box, use the available credentials
my $ mysqluser =
`cat /usr/local/directadmin/conf/mysql.conf | egrep '^user=.*'` ;
my $ mysqlpass =
`cat /usr/local/directadmin/conf/mysql.conf | egrep '^passwd=.*'` ;
$ mysqluser =~ s/user=// ;
$ mysqluser =~ s/[\r\n]// ;
$ mysqlpass =~ s/passwd=// ;
$ mysqlpass =~ s/[\r\n]// ;
$ mysqllogin = "-u $mysqluser -p$mysqlpass" ;
my $ loginstatus = `mysqladmin ping $mysqllogin 2>&1` ;
unless ( $ loginstatus =~ /mysqld is alive/ ) {
badprint
"Attempted to use login credentials from DirectAdmin, but they failed." ;
2015-08-24 08:00:10 +00:00
exit 1 ;
2015-08-19 12:45:24 +00:00
}
}
2018-01-10 14:14:19 +00:00
elsif ( - r "/etc/mysql/debian.cnf"
and $ doremote == 0
and $ opt { 'defaults-file' } eq '' )
{
2015-08-19 12:45:24 +00:00
2018-07-28 23:50:06 +00:00
# We have a Debian maintenance account, use it
2015-08-19 12:45:24 +00:00
$ mysqllogin = "--defaults-file=/etc/mysql/debian.cnf" ;
my $ loginstatus = `$mysqladmincmd $mysqllogin ping 2>&1` ;
if ( $ loginstatus =~ /mysqld is alive/ ) {
goodprint
2018-07-28 23:50:06 +00:00
"Logged in using credentials from Debian maintenance account." ;
2015-08-19 12:45:24 +00:00
return 1 ;
}
else {
2018-11-26 12:57:11 +00:00
badprint
"Attempted to use login credentials from Debian maintenance account, but they failed." ;
2015-08-24 08:00:10 +00:00
exit 1 ;
2015-08-19 12:45:24 +00:00
}
2016-11-03 09:36:59 +00:00
}
2017-08-25 09:12:10 +00:00
elsif ( $ opt { 'defaults-file' } ne '' and - r "$opt{'defaults-file'}" ) {
2016-11-03 09:36:59 +00:00
# defaults-file
debugprint "defaults file detected: $opt{'defaults-file'}" ;
my $ mysqlclidefaults = `$mysqlcmd --print-defaults` ;
debugprint "MySQL Client Default File: $opt{'defaults-file'}" ;
2016-10-24 09:21:56 +00:00
2016-11-03 09:36:59 +00:00
$ mysqllogin = "--defaults-file=" . $ opt { 'defaults-file' } ;
2016-09-26 13:53:32 +00:00
my $ loginstatus = `$mysqladmincmd $mysqllogin ping 2>&1` ;
if ( $ loginstatus =~ /mysqld is alive/ ) {
2016-11-03 09:36:59 +00:00
goodprint "Logged in using credentials from defaults file account." ;
2016-09-26 13:53:32 +00:00
return 1 ;
}
2015-08-19 12:45:24 +00:00
}
2022-12-29 04:13:02 +00:00
elsif ( $ opt { 'defaults-extra-file' } ne ''
and - r "$opt{'defaults-extra-file'}" )
{
2022-09-13 13:55:35 +00:00
# defaults-extra-file
debugprint "defaults extra file detected: $opt{'defaults-extra-file'}" ;
my $ mysqlclidefaults = `$mysqlcmd --print-defaults` ;
2022-12-29 04:13:02 +00:00
debugprint
"MySQL Client Extra Default File: $opt{'defaults-extra-file'}" ;
2022-09-13 13:55:35 +00:00
$ mysqllogin = "--defaults-extra-file=" . $ opt { 'defaults-extra-file' } ;
my $ loginstatus = `$mysqladmincmd $mysqllogin ping 2>&1` ;
if ( $ loginstatus =~ /mysqld is alive/ ) {
2022-12-29 04:13:02 +00:00
goodprint
"Logged in using credentials from extra defaults file account." ;
2022-09-13 13:55:35 +00:00
return 1 ;
}
}
2015-08-19 12:45:24 +00:00
else {
2018-07-28 23:50:06 +00:00
# It's not Plesk or Debian, we should try a login
2015-08-19 12:45:24 +00:00
debugprint "$mysqladmincmd $remotestring ping 2>&1" ;
2023-07-06 06:19:29 +00:00
2023-06-17 15:38:18 +00:00
#my $loginstatus = "";
debugprint "Using mysqlcmd: $mysqlcmd" ;
2023-07-06 06:19:29 +00:00
2023-06-17 15:38:18 +00:00
#if (defined($mysqladmincmd)) {
# infoprint "Using mysqladmin to check login";
# $loginstatus=`$mysqladmincmd $remotestring ping 2>&1`;
#} else {
infoprint "Using mysql to check login" ;
2023-07-06 06:19:29 +00:00
my $ loginstatus =
`$mysqlcmd $remotestring -Nrs -e 'select "mysqld is alive"' --connect-timeout=3 2>&1` ;
2023-06-17 15:38:18 +00:00
#}
2023-07-06 06:19:29 +00:00
2015-08-19 12:45:24 +00:00
if ( $ loginstatus =~ /mysqld is alive/ ) {
2016-08-31 08:30:20 +00:00
2015-08-19 12:45:24 +00:00
# Login went just fine
$ mysqllogin = " $remotestring " ;
2016-08-31 08:30:20 +00:00
# Did this go well because of a .my.cnf file or is there no password set?
2015-08-19 12:45:24 +00:00
my $ userpath = `printenv HOME` ;
if ( length ( $ userpath ) > 0 ) {
chomp ( $ userpath ) ;
}
unless ( - e "${userpath}/.my.cnf" or - e "${userpath}/.mylogin.cnf" )
{
2016-08-31 08:30:20 +00:00
badprint
2023-06-07 17:29:41 +00:00
"SECURITY RISK: Successfully authenticated without password" ;
2015-08-19 12:45:24 +00:00
}
return 1 ;
}
else {
2016-03-29 12:22:45 +00:00
if ( $ opt { 'noask' } == 1 ) {
badprint
"Attempted to use login credentials, but they were invalid" ;
2015-08-24 07:58:52 +00:00
exit 1 ;
}
2016-03-29 12:22:45 +00:00
my ( $ name , $ password ) ;
2016-02-14 00:24:36 +00:00
# If --user is defined no need to ask for username
2016-03-29 12:22:45 +00:00
if ( $ opt { user } ne 0 ) {
2016-02-14 00:24:36 +00:00
$ name = $ opt { user } ;
}
2016-03-29 12:22:45 +00:00
else {
2016-02-14 00:24:36 +00:00
print STDERR "Please enter your MySQL administrative login: " ;
$ name = <STDIN> ;
}
2016-03-29 12:22:45 +00:00
2016-02-14 00:24:36 +00:00
# If --pass is defined no need to ask for password
2016-03-29 12:22:45 +00:00
if ( $ opt { pass } ne 0 ) {
2016-02-14 00:24:36 +00:00
$ password = $ opt { pass } ;
}
2016-03-29 12:22:45 +00:00
else {
print STDERR
"Please enter your MySQL administrative password: " ;
2016-02-14 00:24:36 +00:00
system ( "stty -echo >$devnull 2>&1" ) ;
$ password = <STDIN> ;
system ( "stty echo >$devnull 2>&1" ) ;
}
2015-08-19 12:45:24 +00:00
chomp ( $ password ) ;
chomp ( $ name ) ;
$ mysqllogin = "-u $name" ;
2023-02-10 17:36:32 +00:00
2015-08-19 12:45:24 +00:00
if ( length ( $ password ) > 0 ) {
2016-10-27 13:28:41 +00:00
$ mysqllogin . = " -p'$password'" ;
2015-08-19 12:45:24 +00:00
}
$ mysqllogin . = $ remotestring ;
my $ loginstatus = `$mysqladmincmd ping $mysqllogin 2>&1` ;
if ( $ loginstatus =~ /mysqld is alive/ ) {
2023-03-11 06:48:00 +00:00
2023-02-10 06:22:14 +00:00
#print STDERR "";
2015-08-19 12:45:24 +00:00
if ( ! length ( $ password ) ) {
# Did this go well because of a .my.cnf file or is there no password set?
2016-02-20 16:01:30 +00:00
my $ userpath = `printenv HOME` ;
2015-08-19 12:45:24 +00:00
chomp ( $ userpath ) ;
unless ( - e "$userpath/.my.cnf" ) {
2023-02-02 07:29:45 +00:00
print STDERR "" ;
2015-08-19 12:45:24 +00:00
badprint
2023-05-11 15:21:01 +00:00
"SECURITY RISK: Successfully authenticated without password" ;
2015-08-19 12:45:24 +00:00
}
}
return 1 ;
}
else {
2023-02-10 06:22:14 +00:00
#print STDERR "";
2016-03-29 12:22:45 +00:00
badprint
"Attempted to use login credentials, but they were invalid." ;
2015-08-24 08:00:10 +00:00
exit 1 ;
2015-08-19 12:45:24 +00:00
}
2015-08-24 08:00:10 +00:00
exit 1 ;
2015-08-19 12:45:24 +00:00
}
}
2008-09-08 01:16:39 +00:00
}
2015-07-02 20:06:43 +00:00
# MySQL Request Array
sub select_array {
2015-08-19 12:45:24 +00:00
my $ req = shift ;
debugprint "PERFORM: $req " ;
2016-08-31 11:48:01 +00:00
my @ result = `$mysqlcmd $mysqllogin -Bse "\\w$req" 2>>/dev/null` ;
2016-03-29 12:22:45 +00:00
if ( $? != 0 ) {
2022-06-15 12:43:18 +00:00
badprint "Failed to execute: $req" ;
2016-03-29 12:22:45 +00:00
badprint "FAIL Execute SQL / return code: $?" ;
debugprint "CMD : $mysqlcmd" ;
debugprint "OPTIONS: $mysqllogin" ;
debugprint `$mysqlcmd $mysqllogin -Bse "$req" 2>&1` ;
#exit $?;
}
debugprint "select_array: return code : $?" ;
2015-08-19 12:45:24 +00:00
chomp ( @ result ) ;
return @ result ;
2015-07-02 20:06:43 +00:00
}
2023-03-11 06:48:00 +00:00
2023-04-25 21:05:47 +00:00
# MySQL Request Array
sub select_array_with_headers {
my $ req = shift ;
debugprint "PERFORM: $req " ;
2023-04-25 22:49:53 +00:00
my @ result = `$mysqlcmd $mysqllogin -Bre "\\w$req" 2>>/dev/null` ;
2023-04-25 21:05:47 +00:00
if ( $? != 0 ) {
badprint "Failed to execute: $req" ;
badprint "FAIL Execute SQL / return code: $?" ;
debugprint "CMD : $mysqlcmd" ;
debugprint "OPTIONS: $mysqllogin" ;
debugprint `$mysqlcmd $mysqllogin -Bse "$req" 2>&1` ;
#exit $?;
}
2023-04-25 22:49:53 +00:00
debugprint "select_array_with_headers: return code : $?" ;
2023-04-25 21:05:47 +00:00
chomp ( @ result ) ;
return @ result ;
}
2023-06-07 17:29:41 +00:00
2023-03-01 10:16:44 +00:00
# MySQL Request Array
sub select_csv_file {
2023-03-11 06:48:00 +00:00
my $ tfile = shift ;
my $ req = shift ;
2023-03-01 10:16:44 +00:00
debugprint "PERFORM: $req CSV into $tfile" ;
2023-07-06 06:19:29 +00:00
2023-06-17 20:36:31 +00:00
#return;
2023-04-25 21:05:47 +00:00
my @ result = select_array_with_headers ( $ req ) ;
2023-03-03 14:43:11 +00:00
open ( my $ fh , '>' , $ tfile ) or die "Could not open file '$tfile' $!" ;
for my $ l ( @ result ) {
2023-03-11 06:48:00 +00:00
$ l =~ s/\t/","/g ;
$ l =~ s/^/"/ ;
2023-04-25 21:05:47 +00:00
$ l =~ s/$/"\n/ ;
2023-03-11 06:48:00 +00:00
print $ fh $ l ;
2023-04-25 22:54:23 +00:00
print $ l if $ opt { debug } ;
2023-03-01 10:16:44 +00:00
}
2023-03-03 14:43:11 +00:00
close $ fh ;
2023-06-22 21:00:28 +00:00
infoprint "CSV file $tfile created" ;
2023-03-01 10:16:44 +00:00
}
2023-03-11 06:48:00 +00:00
2018-09-23 09:50:33 +00:00
sub human_size {
2018-11-26 12:57:11 +00:00
my ( $ size , $ n ) = ( shift , 0 ) ;
2018-09-23 09:50:33 +00:00
+ + $ n and $ size /= 1024 until $ size < 1024 ;
2022-09-08 09:46:10 +00:00
return sprintf "%.2f %s" , $ size , ( qw[ bytes KB MB GB TB ] ) [ $ n ] ;
2018-09-23 09:50:33 +00:00
}
2015-07-02 20:06:43 +00:00
# MySQL Request one
sub select_one {
2015-08-19 12:45:24 +00:00
my $ req = shift ;
debugprint "PERFORM: $req " ;
2016-08-31 11:48:01 +00:00
my $ result = `$mysqlcmd $mysqllogin -Bse "\\w$req" 2>>/dev/null` ;
2016-03-29 12:22:45 +00:00
if ( $? != 0 ) {
2022-06-15 12:43:18 +00:00
badprint "Failed to execute: $req" ;
2016-03-29 12:22:45 +00:00
badprint "FAIL Execute SQL / return code: $?" ;
debugprint "CMD : $mysqlcmd" ;
debugprint "OPTIONS: $mysqllogin" ;
debugprint `$mysqlcmd $mysqllogin -Bse "$req" 2>&1` ;
#exit $?;
}
2016-04-11 10:24:49 +00:00
debugprint "select_array: return code : $?" ;
2015-08-19 12:45:24 +00:00
chomp ( $ result ) ;
return $ result ;
2015-07-02 20:06:43 +00:00
}
2017-05-19 00:06:36 +00:00
# MySQL Request one
sub select_one_g {
my $ pattern = shift ;
2017-07-05 09:51:33 +00:00
2017-05-19 00:06:36 +00:00
my $ req = shift ;
debugprint "PERFORM: $req " ;
my @ result = `$mysqlcmd $mysqllogin -re "\\w$req\\G" 2>>/dev/null` ;
if ( $? != 0 ) {
2022-06-15 12:43:18 +00:00
badprint "Failed to execute: $req" ;
2017-05-19 00:06:36 +00:00
badprint "FAIL Execute SQL / return code: $?" ;
debugprint "CMD : $mysqlcmd" ;
debugprint "OPTIONS: $mysqllogin" ;
debugprint `$mysqlcmd $mysqllogin -Bse "$req" 2>&1` ;
#exit $?;
}
debugprint "select_array: return code : $?" ;
chomp ( @ result ) ;
2017-07-05 09:51:33 +00:00
return ( grep { /$pattern/ } @ result ) [ 0 ] ;
2017-05-19 00:06:36 +00:00
}
2017-07-05 09:51:33 +00:00
2017-05-19 00:06:36 +00:00
sub select_str_g {
my $ pattern = shift ;
2017-07-05 09:51:33 +00:00
2017-05-19 00:06:36 +00:00
my $ req = shift ;
2017-07-05 09:51:33 +00:00
my $ str = select_one_g $ pattern , $ req ;
2018-04-04 13:17:57 +00:00
return ( ) unless defined $ str ;
2017-07-05 09:51:33 +00:00
my @ val = split /:/ , $ str ;
2017-05-19 00:06:36 +00:00
shift @ val ;
return trim ( @ val ) ;
}
2017-07-05 09:51:33 +00:00
2022-01-03 17:54:54 +00:00
sub select_user_dbs {
2022-02-04 15:01:22 +00:00
return select_array (
"SELECT DISTINCT TABLE_SCHEMA FROM information_schema.TABLES WHERE TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'percona', 'sys')"
) ;
2022-01-03 17:54:54 +00:00
}
2023-06-07 16:22:02 +00:00
sub select_tables_db {
2022-02-04 15:01:22 +00:00
my $ schema = shift ;
return select_array (
"SELECT DISTINCT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA='$schema'"
) ;
2022-01-03 17:54:54 +00:00
}
2023-06-07 16:22:02 +00:00
sub select_indexes_db {
2022-02-04 15:01:22 +00:00
my $ schema = shift ;
return select_array (
"SELECT DISTINCT INDEX_NAME FROM information_schema.STATISTICS WHERE TABLE_SCHEMA='$schema'"
) ;
2022-01-03 17:54:54 +00:00
}
2022-02-04 15:01:22 +00:00
sub select_views_db {
my $ schema = shift ;
return select_array (
"SELECT DISTINCT TABLE_NAME FROM information_schema.VIEWS WHERE TABLE_SCHEMA='$schema'"
) ;
2022-01-03 17:54:54 +00:00
}
2022-02-04 15:01:22 +00:00
sub select_triggers_db {
my $ schema = shift ;
return select_array (
"SELECT DISTINCT TRIGGER_NAME FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA='$schema'"
) ;
2022-01-03 17:54:54 +00:00
}
2022-02-04 15:01:22 +00:00
sub select_routines_db {
my $ schema = shift ;
return select_array (
"SELECT DISTINCT ROUTINE_NAME FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA='$schema'"
) ;
2022-01-03 17:54:54 +00:00
}
2022-02-04 15:01:22 +00:00
sub select_table_indexes_db {
my $ schema = shift ;
my $ tbname = shift ;
return select_array (
"SELECT INDEX_NAME FROM information_schema.STATISTICS WHERE TABLE_SCHEMA='$schema' AND TABLE_NAME='$tbname'"
) ;
2022-01-03 17:54:54 +00:00
}
2022-02-04 15:01:22 +00:00
sub select_table_columns_db {
my $ schema = shift ;
my $ table = shift ;
return select_array (
"SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='$schema' AND TABLE_NAME='$table'"
) ;
}
2022-01-03 17:54:54 +00:00
2015-07-16 15:14:42 +00:00
sub get_tuning_info {
2015-08-19 12:45:24 +00:00
my @ infoconn = select_array "\\s" ;
my ( $ tkey , $ tval ) ;
@ infoconn =
grep { ! /Threads:/ and ! /Connection id:/ and ! /pager:/ and ! /Using/ }
@ infoconn ;
foreach my $ line ( @ infoconn ) {
if ( $ line =~ /\s*(.*):\s*(.*)/ ) {
debugprint "$1 => $2" ;
$ tkey = $ 1 ;
$ tval = $ 2 ;
chomp ( $ tkey ) ;
chomp ( $ tval ) ;
$ result { 'MySQL Client' } { $ tkey } = $ tval ;
}
}
$ result { 'MySQL Client' } { 'Client Path' } = $ mysqlcmd ;
$ result { 'MySQL Client' } { 'Admin Path' } = $ mysqladmincmd ;
$ result { 'MySQL Client' } { 'Authentication Info' } = $ mysqllogin ;
2015-07-16 15:14:42 +00:00
}
2015-08-19 12:45:24 +00:00
2008-09-08 01:16:39 +00:00
# Populates all of the variable and status hashes
2015-08-19 12:45:24 +00:00
my ( % mystat , % myvar , $ dummyselect , % myrepl , % myslaves ) ;
2016-04-14 20:42:59 +00:00
sub arr2hash {
2016-04-19 14:19:31 +00:00
my $ href = shift ;
my $ harr = shift ;
my $ sep = shift ;
2023-07-06 06:19:29 +00:00
my $ key = '' ;
my $ val = '' ;
2023-06-22 13:15:25 +00:00
2016-04-19 14:19:31 +00:00
$ sep = '\s' unless defined ( $ sep ) ;
foreach my $ line ( @$ harr ) {
2016-08-31 08:30:20 +00:00
next if ( $ line =~ m/^\*\*\*\*\*\*\*/ ) ;
2016-04-14 20:42:59 +00:00
$ line =~ /([a-zA-Z_]*)\s*$sep\s*(.*)/ ;
2023-07-06 06:19:29 +00:00
$ key = $ 1 ;
$ val = $ 2 ;
2023-06-22 13:15:25 +00:00
$$ href { $ key } = $ val ;
2023-07-06 06:19:29 +00:00
2023-06-22 13:15:25 +00:00
debugprint " * $key = $val" if $ key =~ /$opt{dbgpattern}/i ;
2016-04-19 14:19:31 +00:00
}
2016-04-14 20:42:59 +00:00
}
2015-08-19 12:45:24 +00:00
2016-04-14 20:42:59 +00:00
sub get_all_vars {
2016-08-31 08:30:20 +00:00
2015-08-19 12:45:24 +00:00
# We need to initiate at least one query so that our data is useable
$ dummyselect = select_one "SELECT VERSION()" ;
2016-08-31 08:30:20 +00:00
if ( not defined ( $ dummyselect ) or $ dummyselect eq "" ) {
badprint
2022-12-29 04:13:02 +00:00
"You probably do not have enough privileges to run MySQLTuner ..." ;
2016-08-31 08:30:20 +00:00
exit ( 256 ) ;
2016-08-08 15:40:53 +00:00
}
2016-06-23 19:30:22 +00:00
$ dummyselect =~ s/(.*?)\-.*/$1/ ;
2015-08-19 12:45:24 +00:00
debugprint "VERSION: " . $ dummyselect . "" ;
$ result { 'MySQL Client' } { 'Version' } = $ dummyselect ;
2016-04-19 14:19:31 +00:00
2023-06-22 13:24:33 +00:00
my @ mysqlvarlist = select_array ( "SHOW VARIABLES" ) ;
2016-04-29 10:56:24 +00:00
push ( @ mysqlvarlist , select_array ( "SHOW GLOBAL VARIABLES" ) ) ;
2016-04-19 14:19:31 +00:00
arr2hash ( \ % myvar , \ @ mysqlvarlist ) ;
2016-06-02 07:23:46 +00:00
$ result { 'Variables' } = \ % myvar ;
2016-04-19 14:19:31 +00:00
2016-04-29 10:56:24 +00:00
my @ mysqlstatlist = select_array ( "SHOW STATUS" ) ;
push ( @ mysqlstatlist , select_array ( "SHOW GLOBAL STATUS" ) ) ;
2016-04-19 14:19:31 +00:00
arr2hash ( \ % mystat , \ @ mysqlstatlist ) ;
2016-06-02 07:23:46 +00:00
$ result { 'Status' } = \ % mystat ;
2018-11-26 12:57:11 +00:00
unless ( defined ( $ myvar { 'innodb_support_xa' } ) ) {
$ myvar { 'innodb_support_xa' } = 'ON' ;
2018-08-06 10:38:06 +00:00
}
2019-09-25 20:05:45 +00:00
$ mystat { 'Uptime' } = 1
unless defined ( $ mystat { 'Uptime' } )
and $ mystat { 'Uptime' } > 0 ;
2016-04-04 15:23:43 +00:00
$ myvar { 'have_galera' } = "NO" ;
2018-11-26 12:57:11 +00:00
if ( defined ( $ myvar { 'wsrep_provider_options' } )
&& $ myvar { 'wsrep_provider_options' } ne ""
2018-09-20 14:34:07 +00:00
&& $ myvar { 'wsrep_on' } ne "OFF" )
2016-04-19 14:19:31 +00:00
{
2016-04-04 15:23:43 +00:00
$ myvar { 'have_galera' } = "YES" ;
2016-04-19 14:19:31 +00:00
debugprint "Galera options: " . $ myvar { 'wsrep_provider_options' } ;
2016-04-04 15:23:43 +00:00
}
2016-04-14 20:49:21 +00:00
2015-08-19 12:45:24 +00:00
# Workaround for MySQL bug #59393 wrt. ignore-builtin-innodb
if ( ( $ myvar { 'ignore_builtin_innodb' } || "" ) eq "ON" ) {
$ myvar { 'have_innodb' } = "NO" ;
}
2016-03-29 12:22:45 +00:00
2016-11-28 16:39:41 +00:00
# Support GTID MODE FOR MARIADB
2021-01-27 07:03:28 +00:00
# Issue MariaDB GTID mode #513
$ myvar { 'gtid_mode' } = 'ON'
2021-02-05 14:25:09 +00:00
if ( defined ( $ myvar { 'gtid_current_pos' } )
and $ myvar { 'gtid_current_pos' } ne '' ) ;
2016-11-28 16:39:41 +00:00
2022-01-15 17:22:47 +00:00
# Whether the server uses a thread pool to handle client connections
# MariaDB: thread_handling = pool-of-threads
# MySQL: thread_handling = loaded-dynamically
2016-03-22 14:20:18 +00:00
$ myvar { 'have_threadpool' } = "NO" ;
2022-02-04 15:01:22 +00:00
if (
defined ( $ myvar { 'thread_handling' } )
and ( $ myvar { 'thread_handling' } eq 'pool-of-threads'
|| $ myvar { 'thread_handling' } eq 'loaded-dynamically' )
)
2016-03-29 12:22:45 +00:00
{
2016-03-22 14:20:18 +00:00
$ myvar { 'have_threadpool' } = "YES" ;
}
2016-03-29 12:22:45 +00:00
2015-08-19 12:45:24 +00:00
# have_* for engines is deprecated and will be removed in MySQL 5.6;
# check SHOW ENGINES and set corresponding old style variables.
# Also works around MySQL bug #59393 wrt. skip-innodb
my @ mysqlenginelist = select_array "SHOW ENGINES" ;
foreach my $ line ( @ mysqlenginelist ) {
if ( $ line =~ /^([a-zA-Z_]+)\s+(\S+)/ ) {
my $ engine = lc ( $ 1 ) ;
if ( $ engine eq "federated" || $ engine eq "blackhole" ) {
$ engine . = "_engine" ;
}
elsif ( $ engine eq "berkeleydb" ) {
$ engine = "bdb" ;
}
my $ val = ( $ 2 eq "DEFAULT" ) ? "YES" : $ 2 ;
$ myvar { "have_$engine" } = $ val ;
$ result { 'Storage Engines' } { $ engine } = $ 2 ;
}
}
2021-10-15 11:56:27 +00:00
2021-10-15 11:43:07 +00:00
#debugprint Dumper(@mysqlenginelist);
2021-07-02 14:41:36 +00:00
my @ mysqlslave ;
2021-07-02 16:31:21 +00:00
if ( mysql_version_eq ( 8 ) or mysql_version_ge ( 10 , 5 ) ) {
2021-08-26 14:21:23 +00:00
@ mysqlslave = select_array ( "SHOW REPLICA STATUS\\G" ) ;
2021-07-02 16:31:21 +00:00
}
else {
2021-08-26 14:21:23 +00:00
@ mysqlslave = select_array ( "SHOW SLAVE STATUS\\G" ) ;
2021-07-02 14:41:36 +00:00
}
2016-04-19 14:19:31 +00:00
arr2hash ( \ % myrepl , \ @ mysqlslave , ':' ) ;
2016-06-02 07:23:46 +00:00
$ result { 'Replication' } { 'Status' } = \ % myrepl ;
2021-07-02 14:41:36 +00:00
my @ mysqlslaves ;
2021-07-02 16:31:21 +00:00
if ( mysql_version_eq ( 8 ) or mysql_version_ge ( 10 , 5 ) ) {
2021-08-26 14:21:23 +00:00
@ mysqlslaves = select_array "SHOW SLAVE STATUS" ;
2021-07-02 16:31:21 +00:00
}
else {
2021-08-26 14:21:23 +00:00
@ mysqlslaves = select_array ( "SHOW SLAVE HOSTS\\G" ) ;
2021-07-02 14:41:36 +00:00
}
2021-07-02 16:31:21 +00:00
my @ lineitems = ( ) ;
2015-08-19 12:45:24 +00:00
foreach my $ line ( @ mysqlslaves ) {
debugprint "L: $line " ;
2023-03-22 15:34:10 +00:00
@ lineitems = split /\s+/ , $ line ;
$ myslaves { $ lineitems [ 0 ] } = $ line ;
2015-08-19 12:45:24 +00:00
$ result { 'Replication' } { 'Slaves' } { $ lineitems [ 0 ] } = $ lineitems [ 4 ] ;
}
2008-09-08 01:16:39 +00:00
}
2016-03-22 13:44:01 +00:00
sub remove_cr {
2016-08-30 15:20:56 +00:00
return map {
my $ line = $ _ ;
$ line =~ s/\n$//g ;
$ line =~ s/^\s+$//g ;
$ line ;
} @ _ ;
2016-03-22 13:44:01 +00:00
}
2016-03-29 12:22:45 +00:00
2016-03-22 13:44:01 +00:00
sub remove_empty {
grep { $ _ ne '' } @ _ ;
}
2016-03-29 12:22:45 +00:00
2016-12-02 14:24:52 +00:00
sub grep_file_contents {
my $ file = shift ;
2017-02-07 05:56:17 +00:00
my $ patt ;
2016-12-02 14:24:52 +00:00
}
2017-02-07 05:56:17 +00:00
2016-03-22 13:44:01 +00:00
sub get_file_contents {
2015-08-19 12:45:24 +00:00
my $ file = shift ;
2016-08-31 08:30:20 +00:00
open ( my $ fh , "<" , $ file ) or die "Can't open $file for read: $!" ;
2016-08-30 11:27:13 +00:00
my @ lines = <$fh> ;
close $ fh or die "Cannot close $file: $!" ;
2016-08-30 15:20:56 +00:00
@ lines = remove_cr @ lines ;
2015-08-19 12:45:24 +00:00
return @ lines ;
2015-06-12 14:09:59 +00:00
}
2016-03-22 13:44:01 +00:00
sub get_basic_passwords {
return get_file_contents ( shift ) ;
}
2017-09-24 12:45:13 +00:00
sub get_log_file_real_path {
2018-01-10 14:14:19 +00:00
my $ file = shift ;
2017-09-24 12:45:13 +00:00
my $ hostname = shift ;
2018-01-10 14:14:19 +00:00
my $ datadir = shift ;
2017-09-24 12:45:13 +00:00
if ( - f "$file" ) {
return $ file ;
}
2019-09-25 22:41:10 +00:00
elsif ( - f "$hostname.log" ) {
return "$hostname.log" ;
}
2017-09-24 12:45:13 +00:00
elsif ( - f "$hostname.err" ) {
2018-01-10 14:14:19 +00:00
return "$hostname.err" ;
2017-09-24 12:45:13 +00:00
}
2019-09-25 22:41:10 +00:00
elsif ( - f "$datadir$hostname.err" ) {
2017-09-24 12:45:13 +00:00
return "$datadir$hostname.err" ;
}
2019-09-25 22:41:10 +00:00
elsif ( - f "$datadir$hostname.log" ) {
return "$datadir$hostname.log" ;
}
2021-02-05 14:25:09 +00:00
elsif ( - f "$datadir" . "mysql_error.log" ) {
return "$datadir" . "mysql_error.log" ;
2019-09-25 22:41:10 +00:00
}
2021-02-05 14:25:09 +00:00
elsif ( - f "/var/log/mysql.log" ) {
2019-09-25 22:41:10 +00:00
return "/var/log/mysql.log" ;
}
elsif ( - f "/var/log/mysqld.log" ) {
return "/var/log/mysqld.log" ;
}
elsif ( - f "/var/log/mysql/$hostname.err" ) {
return "/var/log/mysql/$hostname.err" ;
}
elsif ( - f "/var/log/mysql/$hostname.log" ) {
return "/var/log/mysql/$hostname.log" ;
}
2021-02-05 14:25:09 +00:00
elsif ( - f "/var/log/mysql/" . "mysql_error.log" ) {
return "/var/log/mysql/" . "mysql_error.log" ;
2019-09-25 22:41:10 +00:00
}
2017-09-24 12:45:13 +00:00
else {
return $ file ;
}
}
2018-02-18 04:59:38 +00:00
sub log_file_recommendations {
2023-06-07 17:29:41 +00:00
if ( is_remote eq 1 ) {
infoprint "Skipping error log files checks on remote host" ;
2023-06-12 12:48:35 +00:00
return ;
2023-06-07 16:22:02 +00:00
}
2021-01-30 01:31:00 +00:00
my $ fh ;
2021-02-05 14:25:09 +00:00
$ myvar { 'log_error' } = $ opt { 'server-log' }
|| get_log_file_real_path ( $ myvar { 'log_error' } , $ myvar { 'hostname' } ,
2018-01-10 14:14:19 +00:00
$ myvar { 'datadir' } ) ;
2019-09-25 22:41:10 +00:00
2016-12-02 14:24:52 +00:00
subheaderprint "Log file Recommendations" ;
2019-10-01 22:07:46 +00:00
if ( "$myvar{'log_error'}" eq "stderr" ) {
2022-06-23 12:31:46 +00:00
badprint
"log_error is set to $myvar{'log_error'}, but this script can't read stderr" ;
2021-02-05 14:25:09 +00:00
return ;
2019-10-01 22:07:46 +00:00
}
2021-01-30 01:31:00 +00:00
elsif ( $ myvar { 'log_error' } =~ /^(docker|podman|kubectl):(.*)/ ) {
open ( $ fh , '-|' , "$1 logs --tail=$maxlines '$2'" )
2021-02-05 14:25:09 +00:00
// die "Can't start $1 $!" ;
2021-01-30 01:31:00 +00:00
goodprint "Log from cloud` $myvar{'log_error'} exists" ;
2017-02-07 05:56:17 +00:00
}
2021-02-05 14:25:09 +00:00
elsif ( $ myvar { 'log_error' } =~ /^systemd:(.*)/ ) {
2021-01-30 01:31:00 +00:00
open ( $ fh , '-|' , "journalctl -n $maxlines -b -u '$1'" )
2021-02-05 14:25:09 +00:00
// die "Can't start journalctl $!" ;
2021-01-30 01:31:00 +00:00
goodprint "Log journal` $myvar{'log_error'} exists" ;
2017-02-07 05:56:17 +00:00
}
2021-01-30 01:31:00 +00:00
elsif ( - f "$myvar{'log_error'}" ) {
goodprint "Log file $myvar{'log_error'} exists" ;
my $ size = ( stat $ myvar { 'log_error' } ) [ 7 ] ;
infoprint "Log file: "
2022-06-15 12:43:18 +00:00
. $ myvar { 'log_error' } . " ("
2021-02-05 14:25:09 +00:00
. hr_bytes_rnd ( $ size ) . ")" ;
2021-01-30 01:31:00 +00:00
if ( $ size > 0 ) {
goodprint "Log file $myvar{'log_error'} is not empty" ;
if ( $ size < 32 * 1024 * 1024 ) {
2023-03-27 16:12:52 +00:00
goodprint "Log file $myvar{'log_error'} is smaller than 32 MB" ;
2021-01-30 01:31:00 +00:00
}
else {
2023-03-27 16:12:52 +00:00
badprint "Log file $myvar{'log_error'} is bigger than 32 MB" ;
2021-01-30 01:31:00 +00:00
push @ generalrec ,
$ myvar { 'log_error' }
2023-03-27 16:12:52 +00:00
. " is > 32MB, you should analyze why or implement a rotation log strategy such as logrotate!" ;
2021-01-30 01:31:00 +00:00
}
}
else {
infoprint
2021-01-29 23:23:56 +00:00
"Log file $myvar{'log_error'} is empty. Assuming log-rotation. Use --server-log={file} for explicit file" ;
2021-01-30 01:31:00 +00:00
return ;
2021-02-05 14:25:09 +00:00
}
if ( ! open ( $ fh , '<' , $ myvar { 'log_error' } ) ) {
2021-01-30 01:31:00 +00:00
badprint "Log file $myvar{'log_error'} isn't readable." ;
return ;
}
goodprint "Log file $myvar{'log_error'} is readable." ;
2017-02-07 05:56:17 +00:00
2021-02-05 14:25:09 +00:00
if ( $ maxlines * 80 < $ size ) {
seek ( $ fh , - $ maxlines * 80 , 2 ) ;
<$fh> ; # discard line fragment
}
2017-02-07 05:56:17 +00:00
}
else {
2021-01-30 01:31:00 +00:00
badprint "Log file $myvar{'log_error'} doesn't exist" ;
return ;
2017-02-07 05:56:17 +00:00
}
my $ numLi = 0 ;
2016-12-07 13:31:51 +00:00
my $ nbWarnLog = 0 ;
2017-02-07 05:56:17 +00:00
my $ nbErrLog = 0 ;
2016-12-07 13:31:51 +00:00
my @ lastShutdowns ;
my @ lastStarts ;
2017-11-28 13:11:39 +00:00
2017-10-06 00:05:20 +00:00
while ( my $ logLi = <$fh> ) {
chomp $ logLi ;
2017-02-07 05:56:17 +00:00
$ numLi + + ;
2021-02-05 14:25:09 +00:00
debugprint "$numLi: $logLi"
if $ logLi =~ /warning|error/i and $ logLi !~ /Logging to/ ;
2023-03-22 15:34:10 +00:00
$ nbErrLog + + if $ logLi =~ /error/i and $ logLi !~ /Logging to/ ;
2021-02-05 14:25:09 +00:00
$ nbWarnLog + + if $ logLi =~ /warning/i ;
2017-02-07 05:56:17 +00:00
push @ lastShutdowns , $ logLi
if $ logLi =~ /Shutdown complete/ and $ logLi !~ /Innodb/i ;
push @ lastStarts , $ logLi if $ logLi =~ /ready for connections/ ;
2016-12-07 13:31:51 +00:00
}
2017-10-06 00:05:20 +00:00
close $ fh ;
2017-11-28 13:11:39 +00:00
2016-12-07 13:31:51 +00:00
if ( $ nbWarnLog > 0 ) {
2017-02-07 05:56:17 +00:00
badprint "$myvar{'log_error'} contains $nbWarnLog warning(s)." ;
2021-09-27 10:25:12 +00:00
push @ generalrec , "Check warning line(s) in $myvar{'log_error'} file" ;
2017-02-07 05:56:17 +00:00
}
else {
goodprint "$myvar{'log_error'} doesn't contain any warning." ;
2016-12-07 13:31:51 +00:00
}
if ( $ nbErrLog > 0 ) {
2017-02-07 05:56:17 +00:00
badprint "$myvar{'log_error'} contains $nbErrLog error(s)." ;
2021-07-17 06:35:44 +00:00
push @ generalrec , "Check error line(s) in $myvar{'log_error'} file" ;
2016-12-07 13:31:51 +00:00
}
2017-02-07 05:56:17 +00:00
else {
goodprint "$myvar{'log_error'} doesn't contain any error." ;
}
2016-12-07 13:31:51 +00:00
infoprint scalar @ lastStarts . " start(s) detected in $myvar{'log_error'}" ;
my $ nStart = 0 ;
2017-02-07 05:56:17 +00:00
my $ nEnd = 10 ;
2016-12-07 13:31:51 +00:00
if ( scalar @ lastStarts < $ nEnd ) {
$ nEnd = scalar @ lastStarts ;
}
2017-02-07 05:56:17 +00:00
for my $ startd ( reverse @ lastStarts [ - $ nEnd .. - 1 ] ) {
2016-12-07 13:31:51 +00:00
$ nStart + + ;
infoprint "$nStart) $startd" ;
}
2017-02-07 05:56:17 +00:00
infoprint scalar @ lastShutdowns
. " shutdown(s) detected in $myvar{'log_error'}" ;
$ nStart = 0 ;
$ nEnd = 10 ;
2016-12-07 13:31:51 +00:00
if ( scalar @ lastShutdowns < $ nEnd ) {
2017-02-07 05:56:17 +00:00
$ nEnd = scalar @ lastShutdowns ;
2016-12-07 13:31:51 +00:00
}
2017-02-07 05:56:17 +00:00
for my $ shutd ( reverse @ lastShutdowns [ - $ nEnd .. - 1 ] ) {
$ nStart + + ;
infoprint "$nStart) $shutd" ;
2016-12-07 13:31:51 +00:00
}
2016-12-02 14:24:52 +00:00
2017-02-07 05:56:17 +00:00
#exit 0;
}
2016-12-02 14:24:52 +00:00
2016-01-05 23:57:34 +00:00
sub cve_recommendations {
2016-04-19 14:19:31 +00:00
subheaderprint "CVE Security Recommendations" ;
2016-03-29 12:22:45 +00:00
unless ( defined ( $ opt { cvefile } ) && - f "$opt{cvefile}" ) {
2016-01-06 00:17:05 +00:00
infoprint "Skipped due to --cvefile option undefined" ;
2016-01-05 23:57:34 +00:00
return ;
}
2017-03-06 14:17:43 +00:00
#$mysqlvermajor=10;
#$mysqlverminor=1;
#$mysqlvermicro=17;
2016-08-31 08:30:20 +00:00
#prettyprint "Look for related CVE for $myvar{'version'} or lower in $opt{cvefile}";
2016-03-29 12:22:45 +00:00
my $ cvefound = 0 ;
2016-08-31 08:30:20 +00:00
open ( my $ fh , "<" , $ opt { cvefile } )
or die "Can't open $opt{cvefile} for read: $!" ;
2016-08-30 11:27:13 +00:00
while ( my $ cveline = <$fh> ) {
2016-03-29 12:22:45 +00:00
my @ cve = split ( ';' , $ cveline ) ;
2016-08-31 08:30:20 +00:00
debugprint
"Comparing $mysqlvermajor\.$mysqlverminor\.$mysqlvermicro with $cve[1]\.$cve[2]\.$cve[3] : "
. ( mysql_version_le ( $ cve [ 1 ] , $ cve [ 2 ] , $ cve [ 3 ] ) ? '<=' : '>' ) ;
2016-08-29 15:10:26 +00:00
# Avoid not major/minor version corresponding CVEs
2016-08-31 08:30:20 +00:00
next
unless ( int ( $ cve [ 1 ] ) == $ mysqlvermajor
&& int ( $ cve [ 2 ] ) == $ mysqlverminor ) ;
if ( int ( $ cve [ 3 ] ) >= $ mysqlvermicro ) {
2016-08-29 15:10:26 +00:00
badprint "$cve[4](<= $cve[1]\.$cve[2]\.$cve[3]) : $cve[6]" ;
2016-08-31 08:30:20 +00:00
$ result { 'CVE' } { 'List' } { $ cvefound } =
"$cve[4](<= $cve[1]\.$cve[2]\.$cve[3]) : $cve[6]" ;
2016-03-29 12:22:45 +00:00
$ cvefound + + ;
}
2016-01-05 23:57:34 +00:00
}
2016-08-30 11:27:13 +00:00
close $ fh or die "Cannot close $opt{cvefile}: $!" ;
2016-08-31 08:30:20 +00:00
$ result { 'CVE' } { 'nb' } = $ cvefound ;
2016-08-31 07:17:03 +00:00
2016-08-31 08:30:20 +00:00
my $ cve_warning_notes = "" ;
2016-03-29 12:22:45 +00:00
if ( $ cvefound == 0 ) {
goodprint "NO SECURITY CVE FOUND FOR YOUR VERSION" ;
return ;
}
2016-08-31 08:30:20 +00:00
if ( $ mysqlvermajor eq 5 and $ mysqlverminor eq 5 ) {
infoprint
"False positive CVE(s) for MySQL and MariaDB 5.5.x can be found." ;
2022-06-30 12:46:54 +00:00
infoprint "Check carefully each CVE for those particular versions" ;
2016-08-31 07:17:03 +00:00
}
2016-01-05 23:57:34 +00:00
badprint $ cvefound . " CVE(s) found for your MySQL release." ;
2016-03-29 12:22:45 +00:00
push ( @ generalrec ,
$ cvefound
. " CVE(s) found for your MySQL release. Consider upgrading your version !"
) ;
2016-01-05 23:57:34 +00:00
}
2016-03-21 16:11:20 +00:00
sub get_opened_ports {
2016-03-29 12:22:45 +00:00
my @ opened_ports = `netstat -ltn` ;
2016-08-30 15:20:56 +00:00
@ opened_ports = map {
my $ v = $ _ ;
$ v =~ s/.*:(\d+)\s.*$/$1/ ;
$ v =~ s/\D//g ;
$ v ;
2016-03-29 12:22:45 +00:00
} @ opened_ports ;
@ opened_ports = sort { $ a <=> $ b } grep { ! /^$/ } @ opened_ports ;
2021-10-15 11:56:27 +00:00
#debugprint Dumper \@opened_ports;
2016-08-31 08:30:20 +00:00
$ result { 'Network' } { 'TCP Opened' } = \ @ opened_ports ;
2016-03-29 12:22:45 +00:00
return @ opened_ports ;
2016-03-21 16:11:20 +00:00
}
sub is_open_port {
2016-03-29 12:22:45 +00:00
my $ port = shift ;
if ( grep { /^$port$/ } get_opened_ports ) {
return 1 ;
}
return 0 ;
2016-03-21 16:11:20 +00:00
}
2016-03-22 13:44:01 +00:00
sub get_process_memory {
2016-03-29 12:22:45 +00:00
my $ pid = shift ;
2016-05-10 09:34:30 +00:00
my @ mem = `ps -p $pid -o rss` ;
return 0 if scalar @ mem != 2 ;
2016-08-31 08:30:20 +00:00
return $ mem [ 1 ] * 1024 ;
2016-03-22 13:44:01 +00:00
}
sub get_other_process_memory {
2018-11-26 12:57:11 +00:00
return 0 if ( $ opt { tbstat } == 0 ) ;
2016-05-19 15:06:12 +00:00
my @ procs = `ps eaxo pid,command` ;
2016-08-30 15:20:56 +00:00
@ procs = map {
my $ v = $ _ ;
$ v =~ s/.*PID.*// ;
$ v =~ s/.*mysqld.*// ;
$ v =~ s/.*\[.*\].*// ;
$ v =~ s/^\s+$//g ;
$ v =~ s/.*PID.*CMD.*// ;
$ v =~ s/.*systemd.*// ;
$ v =~ s/\s*?(\d+)\s*.*/$1/g ;
$ v ;
2016-03-29 12:22:45 +00:00
} @ procs ;
2016-08-30 15:20:56 +00:00
@ procs = remove_cr @ procs ;
2016-03-29 12:22:45 +00:00
@ procs = remove_empty @ procs ;
my $ totalMemOther = 0 ;
map { $ totalMemOther += get_process_memory ( $ _ ) ; } @ procs ;
return $ totalMemOther ;
2016-03-22 13:44:01 +00:00
}
sub get_os_release {
2016-04-19 14:19:31 +00:00
if ( - f "/etc/lsb-release" ) {
2016-04-13 13:39:40 +00:00
my @ info_release = get_file_contents "/etc/lsb-release" ;
2018-02-22 14:29:33 +00:00
my $ os_release = $ info_release [ 3 ] ;
2018-02-18 04:59:50 +00:00
$ os_release =~ s/.*="// ;
$ os_release =~ s/"$// ;
return $ os_release ;
2016-04-19 14:19:31 +00:00
}
2016-04-13 13:39:40 +00:00
2016-04-19 14:19:31 +00:00
if ( - f "/etc/system-release" ) {
2016-03-30 11:44:30 +00:00
my @ info_release = get_file_contents "/etc/system-release" ;
return $ info_release [ 0 ] ;
2016-04-19 14:19:31 +00:00
}
2016-03-30 11:44:30 +00:00
2016-04-19 14:19:31 +00:00
if ( - f "/etc/os-release" ) {
2016-03-30 11:44:30 +00:00
my @ info_release = get_file_contents "/etc/os-release" ;
2018-02-22 14:29:33 +00:00
my $ os_release = $ info_release [ 0 ] ;
2018-02-18 04:59:50 +00:00
$ os_release =~ s/.*="// ;
$ os_release =~ s/"$// ;
return $ os_release ;
2016-04-19 14:19:31 +00:00
}
2016-03-30 11:44:30 +00:00
2016-04-19 14:19:31 +00:00
if ( - f "/etc/issue" ) {
2016-03-30 11:44:30 +00:00
my @ info_release = get_file_contents "/etc/issue" ;
2018-02-22 14:29:33 +00:00
my $ os_release = $ info_release [ 0 ] ;
2018-02-18 04:59:50 +00:00
$ os_release =~ s/\s+\\n.*// ;
return $ os_release ;
2016-04-19 14:19:31 +00:00
}
2016-03-30 11:44:30 +00:00
return "Unknown OS release" ;
2016-03-22 13:44:01 +00:00
}
2016-12-27 10:16:17 +00:00
sub get_fs_info {
2022-02-04 19:20:13 +00:00
my @ sinfo = `df -P | grep '%'` ;
2016-03-29 12:22:45 +00:00
my @ iinfo = `df -Pi| grep '%'` ;
2022-02-04 19:20:13 +00:00
shift @ sinfo ;
2016-03-25 13:32:15 +00:00
shift @ iinfo ;
2022-02-07 22:34:34 +00:00
2016-03-25 13:32:15 +00:00
foreach my $ info ( @ sinfo ) {
2022-02-07 22:34:34 +00:00
2022-02-04 19:20:13 +00:00
#exit(0);
if ( $ info =~ /.*?(\d+)\s+(\d+)\s+(\d+)\s+(\d+)%\s+(.*)$/ ) {
next if $ 5 =~ m {(run|dev|sys|proc|snap|init)} ;
if ( $ 4 > 85 ) {
2022-02-07 22:34:34 +00:00
badprint "mount point $5 is using $4 % total space ("
. human_size ( $ 2 * 1024 ) . " / "
. human_size ( $ 1 * 1024 ) . ")" ;
2022-02-04 19:20:13 +00:00
push ( @ generalrec , "Add some space to $4 mountpoint." ) ;
2016-03-29 12:22:45 +00:00
}
else {
2022-02-07 22:34:34 +00:00
infoprint "mount point $5 is using $4 % total space ("
. human_size ( $ 2 * 1024 ) . " / "
. human_size ( $ 1 * 1024 ) . ")" ;
2016-03-29 12:22:45 +00:00
}
2022-02-07 22:34:34 +00:00
$ result { 'Filesystem' } { 'Space Pct' } { $ 5 } = $ 4 ;
$ result { 'Filesystem' } { 'Used Space' } { $ 5 } = $ 2 ;
$ result { 'Filesystem' } { 'Free Space' } { $ 5 } = $ 3 ;
2022-02-04 19:20:13 +00:00
$ result { 'Filesystem' } { 'Total Space' } { $ 5 } = $ 1 ;
2016-03-29 12:22:45 +00:00
}
}
2016-03-22 13:44:01 +00:00
2016-08-30 15:20:56 +00:00
@ iinfo = map {
my $ v = $ _ ;
$ v =~ s/.*\s(\d+)%\s+(.*)/$1\t$2/g ;
$ v ;
} @ iinfo ;
2016-03-25 13:32:15 +00:00
foreach my $ info ( @ iinfo ) {
2023-09-04 13:32:52 +00:00
next if $ info =~ m {(\d+)\t/(run|dev|sys|proc|snap)($|/)} ;
2016-03-29 12:22:45 +00:00
if ( $ info =~ /(\d+)\t(.*)/ ) {
if ( $ 1 > 85 ) {
badprint "mount point $2 is using $1 % of max allowed inodes" ;
push ( @ generalrec ,
2023-09-04 13:14:42 +00:00
"Cleanup files from $2 mountpoint or reformat your filesystem."
2016-03-29 12:22:45 +00:00
) ;
}
else {
infoprint "mount point $2 is using $1 % of max allowed inodes" ;
}
2016-08-31 08:30:20 +00:00
$ result { 'Filesystem' } { 'Inode Pct' } { $ 2 } = $ 1 ;
2016-03-29 12:22:45 +00:00
}
2016-03-22 13:44:01 +00:00
}
2016-03-25 13:32:15 +00:00
}
2016-03-22 13:44:01 +00:00
2016-04-19 14:19:31 +00:00
sub merge_hash {
my $ h1 = shift ;
my $ h2 = shift ;
my % result = { } ;
foreach my $ substanceref ( $ h1 , $ h2 ) {
while ( my ( $ k , $ v ) = each %$ substanceref ) {
next if ( exists $ result { $ k } ) ;
$ result { $ k } = $ v ;
}
2016-04-14 20:42:59 +00:00
}
2016-04-19 14:19:31 +00:00
return \ % result ;
2016-04-14 20:42:59 +00:00
}
2016-03-29 12:22:45 +00:00
2016-12-27 10:16:17 +00:00
sub is_virtual_machine {
2021-07-02 16:31:21 +00:00
if ( $^O eq 'linux' ) {
my $ isVm = `grep -Ec '^flags.*\ hypervisor\ ' /proc/cpuinfo` ;
return ( $ isVm == 0 ? 0 : 1 ) ;
2021-07-02 14:55:43 +00:00
}
2021-07-02 16:31:21 +00:00
if ( $^O eq 'freebsd' ) {
my $ isVm = `sysctl -n kern.vm_guest` ;
chomp $ isVm ;
print "FARK DEBUG isVm=[$isVm]" ;
return ( $ isVm eq 'none' ? 0 : 1 ) ;
}
return 0 ;
}
2016-03-21 16:11:20 +00:00
2016-03-25 15:22:07 +00:00
sub infocmd {
2016-03-29 12:22:45 +00:00
my $ cmd = "@_" ;
debugprint "CMD: $cmd" ;
my @ result = `$cmd` ;
2016-08-30 15:20:56 +00:00
@ result = remove_cr @ result ;
2016-03-29 12:22:45 +00:00
for my $ l ( @ result ) {
infoprint "$l" ;
}
2016-03-25 15:22:07 +00:00
}
2016-03-29 12:22:45 +00:00
2016-03-25 15:22:07 +00:00
sub infocmd_tab {
2016-03-29 12:22:45 +00:00
my $ cmd = "@_" ;
debugprint "CMD: $cmd" ;
my @ result = `$cmd` ;
2016-08-30 15:20:56 +00:00
@ result = remove_cr @ result ;
2016-03-29 12:22:45 +00:00
for my $ l ( @ result ) {
infoprint "\t$l" ;
2016-03-21 16:11:20 +00:00
}
2016-03-25 15:22:07 +00:00
}
2016-03-29 12:22:45 +00:00
2016-03-25 15:22:07 +00:00
sub infocmd_one {
2016-03-29 12:22:45 +00:00
my $ cmd = "@_" ;
2018-09-23 07:45:25 +00:00
my @ result = `$cmd 2>&1` ;
2016-08-30 15:20:56 +00:00
@ result = remove_cr @ result ;
2016-03-29 12:22:45 +00:00
return join ', ' , @ result ;
}
2016-12-27 10:16:17 +00:00
sub get_kernel_info {
2016-04-19 14:19:31 +00:00
my @ params = (
2023-06-07 17:29:41 +00:00
'fs.aio-max-nr' , 'fs.aio-nr' ,
'fs.nr_open' , 'fs.file-max' ,
'sunrpc.tcp_fin_timeout' , 'sunrpc.tcp_max_slot_table_entries' ,
'sunrpc.tcp_slot_table_entries' , 'vm.swappiness'
2016-04-19 14:19:31 +00:00
) ;
2016-04-22 15:22:00 +00:00
infoprint "Information about kernel tuning:" ;
2016-04-19 14:19:31 +00:00
foreach my $ param ( @ params ) {
2016-08-09 11:38:47 +00:00
infocmd_tab ( "sysctl $param 2>/dev/null" ) ;
2016-08-31 08:30:20 +00:00
$ result { 'OS' } { 'Config' } { $ param } = `sysctl -n $param 2>/dev/null` ;
2016-04-19 14:19:31 +00:00
}
if ( `sysctl -n vm.swappiness` > 10 ) {
badprint
"Swappiness is > 10, please consider having a value lower than 10" ;
2023-05-11 15:21:01 +00:00
push @ generalrec , "setup swappiness lower or equal to 10" ;
2017-07-05 09:51:33 +00:00
push @ adjvars ,
2023-06-07 17:29:41 +00:00
'vm.swappiness <= 10 (echo 10 > /proc/sys/vm/swappiness) or vm.swappiness=10 in /etc/sysctl.conf' ;
2016-04-19 14:19:31 +00:00
}
else {
infoprint "Swappiness is < 10." ;
}
2016-08-10 09:48:41 +00:00
# only if /proc/sys/sunrpc exists
2016-08-31 08:30:20 +00:00
my $ tcp_slot_entries =
`sysctl -n sunrpc.tcp_slot_table_entries 2>/dev/null` ;
if ( - f "/proc/sys/sunrpc"
and ( $ tcp_slot_entries eq '' or $ tcp_slot_entries < 100 ) )
{
2016-04-19 14:19:31 +00:00
badprint
"Initial TCP slot entries is < 1M, please consider having a value greater than 100" ;
push @ generalrec , "setup Initial TCP slot entries greater than 100" ;
push @ adjvars ,
2023-06-07 17:05:18 +00:00
'sunrpc.tcp_slot_table_entries > 100 (echo 128 > /proc/sys/sunrpc/tcp_slot_table_entries) or sunrpc.tcp_slot_table_entries=128 in /etc/sysctl.conf' ;
2016-04-19 14:19:31 +00:00
}
else {
infoprint "TCP slot entries is > 100." ;
}
2021-08-25 10:01:28 +00:00
if ( - f "/proc/sys/fs/aio-max-nr" ) {
if ( `sysctl -n fs.aio-max-nr` < 1000000 ) {
badprint
2023-06-07 17:05:18 +00:00
"Max running total of the number of max. events is < 1M, please consider having a value greater than 1M" ;
2021-08-25 10:01:28 +00:00
push @ generalrec , "setup Max running number events greater than 1M" ;
push @ adjvars ,
2023-06-07 17:29:41 +00:00
'fs.aio-max-nr > 1M (echo 1048576 > /proc/sys/fs/aio-max-nr) or fs.aio-max-nr=1048576 in /etc/sysctl.conf' ;
2021-08-25 10:01:28 +00:00
}
else {
infoprint "Max Number of AIO events is > 1M." ;
}
}
2023-06-07 17:05:18 +00:00
if ( - f "/proc/sys/fs/nr_open" ) {
if ( `sysctl -n fs.nr_open` < 1000000 ) {
badprint
"Max running total of the number of file open request is < 1M, please consider having a value greater than 1M" ;
2023-06-07 17:29:41 +00:00
push @ generalrec ,
"setup running number of open request greater than 1M" ;
2023-06-07 17:05:18 +00:00
push @ adjvars ,
2023-06-07 17:29:41 +00:00
'fs.aio-nr > 1M (echo 1048576 > /proc/sys/fs/nr_open) or fs.nr_open=1048576 in /etc/sysctl.conf' ;
2023-06-07 17:05:18 +00:00
}
else {
infoprint "Max Number of open file requests is > 1M." ;
}
}
2016-04-19 14:19:31 +00:00
}
2016-03-21 16:11:20 +00:00
2016-12-27 10:16:17 +00:00
sub get_system_info {
2016-08-31 08:30:20 +00:00
$ result { 'OS' } { 'Release' } = get_os_release ( ) ;
2016-03-29 12:22:45 +00:00
infoprint get_os_release ;
if ( is_virtual_machine ) {
infoprint "Machine type : Virtual machine" ;
2016-08-31 08:30:20 +00:00
$ result { 'OS' } { 'Virtual Machine' } = 'YES' ;
2016-03-21 16:11:20 +00:00
}
2016-03-29 12:22:45 +00:00
else {
infoprint "Machine type : Physical machine" ;
2016-08-31 08:30:20 +00:00
$ result { 'OS' } { 'Virtual Machine' } = 'NO' ;
2016-03-29 12:22:45 +00:00
}
2016-08-31 08:30:20 +00:00
$ result { 'Network' } { 'Connected' } = 'NO' ;
2016-04-05 13:49:43 +00:00
`ping -c 1 ipecho.net &>/dev/null` ;
2016-03-29 12:22:45 +00:00
my $ isConnected = $? ;
if ( $? == 0 ) {
infoprint "Internet : Connected" ;
2016-08-31 08:30:20 +00:00
$ result { 'Network' } { 'Connected' } = 'YES' ;
2016-03-21 16:11:20 +00:00
}
2016-03-29 12:22:45 +00:00
else {
badprint "Internet : Disconnected" ;
}
2017-03-13 16:22:05 +00:00
$ result { 'OS' } { 'NbCore' } = cpu_cores ;
infoprint "Number of Core CPU : " . cpu_cores ;
2016-08-31 08:30:20 +00:00
$ result { 'OS' } { 'Type' } = `uname -o` ;
2016-03-29 12:22:45 +00:00
infoprint "Operating System Type : " . infocmd_one "uname -o" ;
2016-08-31 08:30:20 +00:00
$ result { 'OS' } { 'Kernel' } = `uname -r` ;
2016-03-29 12:22:45 +00:00
infoprint "Kernel Release : " . infocmd_one "uname -r" ;
2016-08-31 08:30:20 +00:00
$ result { 'OS' } { 'Hostname' } = `hostname` ;
$ result { 'Network' } { 'Internal Ip' } = `hostname -I` ;
2016-03-29 12:22:45 +00:00
infoprint "Hostname : " . infocmd_one "hostname" ;
infoprint "Network Cards : " ;
infocmd_tab "ifconfig| grep -A1 mtu" ;
infoprint "Internal IP : " . infocmd_one "hostname -I" ;
2018-09-23 19:48:09 +00:00
$ result { 'Network' } { 'Internal Ip' } = `ifconfig| grep -A1 mtu` ;
2016-04-19 14:19:31 +00:00
my $ httpcli = get_http_cli ( ) ;
2016-04-05 13:49:43 +00:00
infoprint "HTTP client found: $httpcli" if defined $ httpcli ;
2016-04-19 14:19:31 +00:00
2016-08-31 08:30:20 +00:00
my $ ext_ip = "" ;
2016-04-19 14:19:31 +00:00
if ( $ httpcli =~ /curl$/ ) {
2017-04-20 22:13:45 +00:00
$ ext_ip = infocmd_one "$httpcli -m 3 ipecho.net/plain" ;
2016-04-18 14:45:34 +00:00
}
elsif ( $ httpcli =~ /wget$/ ) {
2016-08-31 08:30:20 +00:00
2017-04-20 22:13:45 +00:00
$ ext_ip = infocmd_one "$httpcli -t 1 -T 3 -q -O - ipecho.net/plain" ;
2016-04-18 14:45:34 +00:00
}
2016-08-31 08:30:20 +00:00
infoprint "External IP : " . $ ext_ip ;
$ result { 'Network' } { 'External Ip' } = $ ext_ip ;
2023-06-07 17:29:41 +00:00
badprint "External IP : Can't check, no Internet connectivity"
2016-04-19 14:19:31 +00:00
unless defined ( $ httpcli ) ;
2016-03-29 12:22:45 +00:00
infoprint "Name Servers : "
. infocmd_one "grep 'nameserver' /etc/resolv.conf \| awk '{print \$2}'" ;
infoprint "Logged In users : " ;
infocmd_tab "who" ;
2016-08-31 08:30:20 +00:00
$ result { 'OS' } { 'Logged users' } = `who` ;
2023-03-27 16:12:52 +00:00
infoprint "Ram Usages in MB : " ;
2016-04-04 11:58:52 +00:00
infocmd_tab "free -m | grep -v +" ;
2016-08-31 08:30:20 +00:00
$ result { 'OS' } { 'Free Memory RAM' } = `free -m | grep -v +` ;
2016-03-29 12:22:45 +00:00
infoprint "Load Average : " ;
infocmd_tab "top -n 1 -b | grep 'load average:'" ;
2016-08-31 08:30:20 +00:00
$ result { 'OS' } { 'Load Average' } = `top -n 1 -b | grep 'load average:'` ;
2018-09-23 19:48:09 +00:00
infoprint "System Uptime : " ;
infocmd_tab "uptime" ;
2018-11-26 12:57:11 +00:00
$ result { 'OS' } { 'Uptime' } = `uptime` ;
2016-03-25 15:22:07 +00:00
}
2016-03-21 16:11:20 +00:00
sub system_recommendations {
2023-06-07 17:29:41 +00:00
if ( is_remote eq 1 ) {
infoprint "Skipping system checks on remote host" ;
return ;
2023-06-07 16:22:02 +00:00
}
2016-04-19 14:19:31 +00:00
return if ( $ opt { sysstat } == 0 ) ;
subheaderprint "System Linux Recommendations" ;
2016-03-21 16:11:20 +00:00
my $ os = `uname` ;
2016-03-29 12:22:45 +00:00
unless ( $ os =~ /Linux/i ) {
2016-03-21 16:11:20 +00:00
infoprint "Skipped due to non Linux server" ;
return ;
2016-03-29 12:22:45 +00:00
}
2016-04-22 15:22:00 +00:00
prettyprint "Look for related Linux system recommendations" ;
2023-07-06 06:19:29 +00:00
2016-03-22 13:44:01 +00:00
#prettyprint '-'x78;
2016-03-25 15:22:07 +00:00
get_system_info ( ) ;
2023-07-06 06:19:29 +00:00
2023-06-26 07:42:58 +00:00
my $ nb_cpus = cpu_cores ;
2023-07-06 06:19:29 +00:00
if ( $ nb_cpus > 1 ) {
2023-06-26 07:42:58 +00:00
goodprint "There is at least one CPU dedicated to database server." ;
}
2023-07-06 06:19:29 +00:00
else {
badprint
"There is only one CPU, consider dedicated one CPU for your database server" ;
push @ generalrec ,
"Consider increasing number of CPU for your database server" ;
}
2023-10-09 13:05:07 +00:00
if ( $ physical_memory >= 1.5 * 1024 ) {
2023-06-26 07:42:58 +00:00
goodprint "There is at least 1 Gb of RAM dedicated to Linux server." ;
}
2023-07-06 06:19:29 +00:00
else {
badprint
"There is less than 1,5 Gb of RAM, consider dedicated 1 Gb for your Linux server" ;
push @ generalrec ,
"Consider increasing 1,5 / 2 Gb of RAM for your Linux server" ;
}
2016-03-29 12:22:45 +00:00
my $ omem = get_other_process_memory ;
infoprint "User process except mysqld used "
. hr_bytes_rnd ( $ omem ) . " RAM." ;
if ( ( 0.15 * $ physical_memory ) < $ omem ) {
badprint
"Other user process except mysqld used more than 15% of total physical memory "
. percentage ( $ omem , $ physical_memory ) . "% ("
. hr_bytes_rnd ( $ omem ) . " / "
. hr_bytes_rnd ( $ physical_memory ) . ")" ;
push ( @ generalrec ,
2016-04-22 15:22:00 +00:00
"Consider stopping or dedicate server for additional process other than mysqld."
2016-03-29 12:22:45 +00:00
) ;
push ( @ adjvars ,
"DON'T APPLY SETTINGS BECAUSE THERE ARE TOO MANY PROCESSES RUNNING ON THIS SERVER. OOM KILL CAN OCCUR!"
) ;
}
else {
infoprint
"Other user process except mysqld used less than 15% of total physical memory "
. percentage ( $ omem , $ physical_memory ) . "% ("
. hr_bytes_rnd ( $ omem ) . " / "
. hr_bytes_rnd ( $ physical_memory ) . ")" ;
}
if ( $ opt { 'maxportallowed' } > 0 ) {
my @ opened_ports = get_opened_ports ;
infoprint "There is "
. scalar @ opened_ports
. " listening port(s) on this server." ;
if ( scalar ( @ opened_ports ) > $ opt { 'maxportallowed' } ) {
2022-06-30 12:46:54 +00:00
badprint "There are too many listening ports: "
2016-03-29 12:22:45 +00:00
. scalar ( @ opened_ports )
. " opened > "
. $ opt { 'maxportallowed' }
. "allowed." ;
push ( @ generalrec ,
2023-03-28 17:44:04 +00:00
"Consider dedicating a server for your database installation with fewer services running on it!"
2016-03-29 12:22:45 +00:00
) ;
}
else {
2022-06-30 12:46:54 +00:00
goodprint "There are less than "
2016-03-29 12:22:45 +00:00
. $ opt { 'maxportallowed' }
. " opened ports on this server." ;
}
2016-03-21 16:11:20 +00:00
}
2016-03-24 09:21:02 +00:00
2016-03-21 16:41:14 +00:00
foreach my $ banport ( @ banned_ports ) {
2016-03-29 12:22:45 +00:00
if ( is_open_port ( $ banport ) ) {
badprint "Banned port: $banport is opened.." ;
push ( @ generalrec ,
2023-03-29 10:33:47 +00:00
"Port $banport is opened. Consider stopping the program over this port."
2016-03-29 12:22:45 +00:00
) ;
}
else {
goodprint "$banport is not opened." ;
}
2016-03-21 16:41:14 +00:00
}
2016-03-25 13:32:15 +00:00
2022-02-04 19:20:13 +00:00
subheaderprint "Filesystem Linux Recommendations" ;
2016-03-25 13:32:15 +00:00
get_fs_info ;
2022-02-04 19:20:13 +00:00
subheaderprint "Kernel Information Recommendations" ;
2016-04-04 10:12:09 +00:00
get_kernel_info ;
2016-03-21 16:11:20 +00:00
}
2016-03-25 10:57:35 +00:00
2009-09-17 23:13:22 +00:00
sub security_recommendations {
2016-04-11 10:01:01 +00:00
subheaderprint "Security Recommendations" ;
2018-11-26 12:57:11 +00:00
2018-09-23 07:45:25 +00:00
if ( mysql_version_eq ( 8 ) ) {
2023-03-28 17:44:04 +00:00
infoprint "Skipped due to unsupported feature for MySQL 8.0+" ;
2018-09-23 07:45:25 +00:00
return ;
}
2018-11-26 12:57:11 +00:00
2018-09-23 07:45:25 +00:00
#exit 0;
2015-08-19 12:45:24 +00:00
if ( $ opt { skippassword } eq 1 ) {
infoprint "Skipped due to --skippassword option" ;
return ;
}
2016-03-29 12:22:45 +00:00
my $ PASS_COLUMN_NAME = 'password' ;
2021-02-05 14:25:09 +00:00
2020-12-26 09:02:51 +00:00
# New table schema available since mysql-5.7 and mariadb-10.2
# But need to be checked
if ( $ myvar { 'version' } =~ /5\.7|10\.[2-5]\..*MariaDB*/ ) {
2019-09-25 20:05:45 +00:00
my $ password_column_exists =
`$mysqlcmd $mysqllogin -Bse "SELECT 1 FROM information_schema.columns WHERE TABLE_SCHEMA = 'mysql' AND TABLE_NAME = 'user' AND COLUMN_NAME = 'password'" 2>>/dev/null` ;
2020-12-26 09:02:51 +00:00
my $ authstring_column_exists =
`$mysqlcmd $mysqllogin -Bse "SELECT 1 FROM information_schema.columns WHERE TABLE_SCHEMA = 'mysql' AND TABLE_NAME = 'user' AND COLUMN_NAME = 'authentication_string'" 2>>/dev/null` ;
2021-02-05 14:25:09 +00:00
if ( $ password_column_exists && $ authstring_column_exists ) {
2019-09-10 20:06:58 +00:00
$ PASS_COLUMN_NAME =
2019-03-06 13:10:17 +00:00
"IF(plugin='mysql_native_password', authentication_string, password)" ;
2019-09-10 20:06:58 +00:00
}
2020-12-26 09:32:59 +00:00
elsif ( $ authstring_column_exists ) {
2019-09-10 20:06:58 +00:00
$ PASS_COLUMN_NAME = 'authentication_string' ;
}
2021-02-05 14:25:09 +00:00
elsif ( ! $ password_column_exists ) {
2020-12-26 09:02:51 +00:00
infoprint "Skipped due to none of known auth columns exists" ;
return ;
}
2018-03-19 15:33:04 +00:00
}
2015-12-10 10:52:39 +00:00
debugprint "Password column = $PASS_COLUMN_NAME" ;
2016-03-29 12:22:45 +00:00
2022-06-15 16:08:11 +00:00
# IS THERE A ROLE COLUMN
2022-06-23 12:31:46 +00:00
my $ is_role_column = select_one
"select count(*) from information_schema.columns where TABLE_NAME='user' AND TABLE_SCHEMA='mysql' and COLUMN_NAME='IS_ROLE'" ;
my $ extra_user_condition = "" ;
$ extra_user_condition = "IS_ROLE = 'N' AND" if $ is_role_column > 0 ;
2022-06-15 16:08:11 +00:00
my @ mysqlstatlist ;
2022-06-23 12:31:46 +00:00
if ( $ is_role_column > 0 ) {
@ mysqlstatlist = select_array
"SELECT CONCAT(QUOTE(user), '\@', QUOTE(host)) FROM mysql.user WHERE IS_ROLE='Y'" ;
2022-06-15 16:08:11 +00:00
foreach my $ line ( sort @ mysqlstatlist ) {
chomp ( $ line ) ;
infoprint "User $line is User Role" ;
}
}
2022-06-23 12:31:46 +00:00
else {
debugprint "No Role user detected" ;
goodprint "No Role user detected" ;
}
2015-08-19 12:45:24 +00:00
# Looking for Anonymous users
2022-06-15 16:08:11 +00:00
@ mysqlstatlist = select_array
"SELECT CONCAT(QUOTE(user), '\@', QUOTE(host)) FROM mysql.user WHERE $extra_user_condition (TRIM(USER) = '' OR USER IS NULL)" ;
2021-10-15 11:56:27 +00:00
2021-10-15 11:43:07 +00:00
#debugprint Dumper \@mysqlstatlist;
2016-03-29 12:22:45 +00:00
2016-03-21 14:51:16 +00:00
#exit 0;
2015-08-19 12:45:24 +00:00
if ( @ mysqlstatlist ) {
push ( @ generalrec ,
2023-03-27 16:12:52 +00:00
"Remove Anonymous User accounts: there are "
2015-08-19 12:45:24 +00:00
. scalar ( @ mysqlstatlist )
2015-12-10 10:52:39 +00:00
. " anonymous accounts." ) ;
2020-12-08 03:37:21 +00:00
foreach my $ line ( sort @ mysqlstatlist ) {
chomp ( $ line ) ;
2021-02-05 14:25:09 +00:00
badprint "User "
. $ line
. " is an anonymous account. Remove with DROP USER "
. $ line . ";" ;
2020-12-08 03:37:21 +00:00
}
2015-08-19 12:45:24 +00:00
}
else {
2015-11-13 14:54:24 +00:00
goodprint "There are no anonymous accounts for any database users" ;
2015-08-19 12:45:24 +00:00
}
2016-04-29 12:19:46 +00:00
if ( mysql_version_le ( 5 , 1 ) ) {
2016-08-31 08:30:20 +00:00
badprint "No more password checks for MySQL version <=5.1" ;
2022-06-30 12:46:54 +00:00
badprint "MySQL version <=5.1 is deprecated and end of support." ;
2016-08-31 08:30:20 +00:00
return ;
2016-04-29 12:19:46 +00:00
}
2016-08-31 08:30:20 +00:00
2015-08-19 12:45:24 +00:00
# Looking for Empty Password
2021-02-05 14:25:09 +00:00
if ( mysql_version_ge ( 10 , 4 ) ) {
2016-11-03 09:36:59 +00:00
@ mysqlstatlist = select_array
2021-02-04 22:34:43 +00:00
q{ SELECT CONCAT(QUOTE(user), '@', QUOTE(host)) FROM mysql.global_priv WHERE
2022-06-15 16:08:11 +00:00
( user != ''
2021-01-27 06:15:00 +00:00
AND JSON_CONTAINS ( Priv , '"mysql_native_password"' , '$.plugin' ) AND JSON_CONTAINS ( Priv , '""' , '$.authentication_string' )
2022-06-15 16:08:11 +00:00
AND NOT JSON_CONTAINS ( Priv , 'true' , '$.account_locked' )
) } ;
2016-11-03 09:36:59 +00:00
}
else {
@ mysqlstatlist = select_array
2021-02-04 22:34:43 +00:00
" SELECT CONCAT ( QUOTE ( user ) , '\@' , QUOTE ( host ) ) FROM mysql . user WHERE ( $ PASS_COLUMN_NAME = '' OR $ PASS_COLUMN_NAME IS NULL )
2021-01-27 06:15:00 +00:00
AND user != ''
2020-12-08 03:18:03 +00:00
/*!50501 AND plugin NOT IN ('auth_socket', 'unix_socket', 'win_socket', 'auth_pam_compat') */
2020-12-08 03:00:33 +00:00
/*!80000 AND account_locked = 'N' AND password_expired = 'N' */ " ;
2016-09-03 14:11:09 +00:00
}
2015-08-19 12:45:24 +00:00
if ( @ mysqlstatlist ) {
foreach my $ line ( sort @ mysqlstatlist ) {
chomp ( $ line ) ;
badprint "User '" . $ line . "' has no password set." ;
2021-02-05 14:25:09 +00:00
push ( @ generalrec ,
"Set up a Secure Password for $line user: SET PASSWORD FOR $line = PASSWORD('secure_password');"
) ;
2015-08-19 12:45:24 +00:00
}
}
else {
goodprint "All database users have passwords assigned" ;
}
2016-03-29 12:22:45 +00:00
if ( mysql_version_ge ( 5 , 7 ) ) {
my $ valPlugin = select_one (
"select count(*) from information_schema.plugins where PLUGIN_NAME='validate_password' AND PLUGIN_STATUS='ACTIVE'"
) ;
if ( $ valPlugin >= 1 ) {
infoprint
"Bug #80860 MySQL 5.7: Avoid testing password when validate_password is activated" ;
return ;
}
2016-03-25 10:57:35 +00:00
}
2015-08-19 12:45:24 +00:00
# Looking for User with user/ uppercase /capitalise user as password
@ mysqlstatlist = select_array
2021-02-04 22:34:43 +00:00
"SELECT CONCAT(QUOTE(user), '\@', QUOTE(host)) FROM mysql.user WHERE user != '' AND (CAST($PASS_COLUMN_NAME as Binary) = PASSWORD(user) OR CAST($PASS_COLUMN_NAME as Binary) = PASSWORD(UPPER(user)) OR CAST($PASS_COLUMN_NAME as Binary) = PASSWORD(CONCAT(UPPER(LEFT(User, 1)), SUBSTRING(User, 2, LENGTH(User)))))" ;
2015-08-19 12:45:24 +00:00
if ( @ mysqlstatlist ) {
foreach my $ line ( sort @ mysqlstatlist ) {
chomp ( $ line ) ;
2021-02-04 22:34:43 +00:00
badprint "User " . $ line . " has user name as password." ;
2021-02-05 14:25:09 +00:00
push ( @ generalrec ,
"Set up a Secure Password for $line user: SET PASSWORD FOR $line = PASSWORD('secure_password');"
) ;
2015-08-19 12:45:24 +00:00
}
}
@ mysqlstatlist = select_array
2021-02-04 22:04:24 +00:00
"SELECT CONCAT(QUOTE(user), '\@', host) FROM mysql.user WHERE HOST='%'" ;
2015-08-19 12:45:24 +00:00
if ( @ mysqlstatlist ) {
foreach my $ line ( sort @ mysqlstatlist ) {
chomp ( $ line ) ;
2021-02-05 14:25:09 +00:00
my $ luser = ( split /@/ , $ line ) [ 0 ] ;
2021-07-02 14:22:51 +00:00
badprint "User " . $ line
. " does not specify hostname restrictions." ;
2019-10-03 21:15:31 +00:00
push ( @ generalrec ,
2021-07-02 14:22:51 +00:00
"Restrict Host for $luser\@'%' to $luser\@LimitedIPRangeOrLocalhost"
2021-02-05 14:25:09 +00:00
) ;
2019-10-03 21:15:31 +00:00
push ( @ generalrec ,
2021-02-05 14:25:09 +00:00
"RENAME USER $luser\@'%' TO "
. $ luser
. "\@LimitedIPRangeOrLocalhost;" ) ;
2015-08-19 12:45:24 +00:00
}
}
unless ( - f $ basic_password_files ) {
2015-12-10 10:52:39 +00:00
badprint "There is no basic password file list!" ;
2015-08-19 12:45:24 +00:00
return ;
}
my @ passwords = get_basic_passwords $ basic_password_files ;
2015-11-13 14:54:24 +00:00
infoprint "There are "
2015-08-19 12:45:24 +00:00
. scalar ( @ passwords )
. " basic passwords in the list." ;
my $ nbins = 0 ;
my $ passreq ;
if ( @ passwords ) {
2017-02-07 05:56:17 +00:00
my $ nbInterPass = 0 ;
2015-08-19 12:45:24 +00:00
foreach my $ pass ( @ passwords ) {
2016-12-02 14:24:52 +00:00
$ nbInterPass + + ;
2015-08-19 12:45:24 +00:00
$ pass =~ s/\s//g ;
2016-12-02 14:24:52 +00:00
$ pass =~ s/\'/\\\'/g ;
2015-08-19 12:45:24 +00:00
chomp ( $ pass ) ;
# Looking for User with user/ uppercase /capitalise weak password
@ mysqlstatlist =
select_array
2015-12-10 10:52:39 +00:00
"SELECT CONCAT(user, '\@', host) FROM mysql.user WHERE $PASS_COLUMN_NAME = PASSWORD('"
2015-08-19 12:45:24 +00:00
. $ pass
2015-12-10 10:52:39 +00:00
. "') OR $PASS_COLUMN_NAME = PASSWORD(UPPER('"
2015-08-19 12:45:24 +00:00
. $ pass
2016-08-23 22:21:18 +00:00
. "')) OR $PASS_COLUMN_NAME = PASSWORD(CONCAT(UPPER(LEFT('"
2015-08-19 12:45:24 +00:00
. $ pass
2016-08-23 22:21:18 +00:00
. "', 1)), SUBSTRING('"
2015-08-19 12:45:24 +00:00
. $ pass
. "', 2, LENGTH('"
2016-08-23 22:21:18 +00:00
. $ pass . "'))))" ;
2022-06-30 12:46:54 +00:00
debugprint "There are " . scalar ( @ mysqlstatlist ) . " items." ;
2015-08-19 12:45:24 +00:00
if ( @ mysqlstatlist ) {
foreach my $ line ( @ mysqlstatlist ) {
chomp ( $ line ) ;
badprint "User '" . $ line
2016-04-22 15:22:00 +00:00
. "' is using weak password: $pass in a lower, upper or capitalize derivative version." ;
2019-10-03 21:15:31 +00:00
2021-02-05 14:25:09 +00:00
push ( @ generalrec ,
"Set up a Secure Password for $line user: SET PASSWORD FOR '"
. ( split /@/ , $ line ) [ 0 ] . "'\@'"
. ( split /@/ , $ line ) [ 1 ]
. "' = PASSWORD('secure_password');" ) ;
2015-08-19 12:45:24 +00:00
$ nbins + + ;
}
}
2017-02-07 05:56:17 +00:00
debugprint "$nbInterPass / " . scalar ( @ passwords )
if ( $ nbInterPass % 1000 == 0 ) ;
2015-08-19 12:45:24 +00:00
}
}
if ( $ nbins > 0 ) {
2021-02-05 14:25:09 +00:00
push ( @ generalrec ,
$ nbins
. " user(s) used basic or weak password from basic dictionary." ) ;
2015-08-19 12:45:24 +00:00
}
2009-09-17 23:13:22 +00:00
}
2015-08-19 12:45:24 +00:00
sub get_replication_status {
2016-04-19 14:19:31 +00:00
subheaderprint "Replication Metrics" ;
infoprint "Galera Synchronous replication: " . $ myvar { 'have_galera' } ;
2015-08-19 12:45:24 +00:00
if ( scalar ( keys % myslaves ) == 0 ) {
infoprint "No replication slave(s) for this server." ;
}
else {
infoprint "This server is acting as master for "
. scalar ( keys % myslaves )
. " server(s)." ;
}
2018-03-19 16:17:11 +00:00
infoprint "Binlog format: " . $ myvar { 'binlog_format' } ;
2018-08-06 10:38:06 +00:00
infoprint "XA support enabled: " . $ myvar { 'innodb_support_xa' } ;
2018-03-19 16:17:11 +00:00
infoprint "Semi synchronous replication Master: "
2018-03-30 13:44:40 +00:00
. (
2022-06-23 12:31:46 +00:00
(
defined ( $ myvar { 'rpl_semi_sync_master_enabled' } )
or defined ( $ myvar { 'rpl_semi_sync_source_enabled' } )
)
? ( $ myvar { 'rpl_semi_sync_master_enabled' }
// $ myvar { 'rpl_semi_sync_source_enabled' } )
2018-04-26 12:15:59 +00:00
: 'Not Activated'
) ;
2018-03-19 16:17:11 +00:00
infoprint "Semi synchronous replication Slave: "
2018-03-30 13:44:40 +00:00
. (
2022-06-23 12:31:46 +00:00
(
defined ( $ myvar { 'rpl_semi_sync_slave_enabled' } )
or defined ( $ myvar { 'rpl_semi_sync_replica_enabled' } )
)
? ( $ myvar { 'rpl_semi_sync_slave_enabled' }
// $ myvar { 'rpl_semi_sync_replica_enabled' } )
2018-04-26 12:15:59 +00:00
: 'Not Activated'
) ;
2015-08-19 12:45:24 +00:00
if ( scalar ( keys % myrepl ) == 0 and scalar ( keys % myslaves ) == 0 ) {
2018-03-19 16:08:12 +00:00
infoprint "This is a standalone server" ;
2015-08-19 12:45:24 +00:00
return ;
}
if ( scalar ( keys % myrepl ) == 0 ) {
2018-03-19 16:17:11 +00:00
infoprint
"No replication setup for this server or replication not started." ;
2015-08-19 12:45:24 +00:00
return ;
}
2018-03-19 16:08:12 +00:00
2016-08-31 08:30:20 +00:00
$ result { 'Replication' } { 'status' } = \ % myrepl ;
2022-06-23 12:31:46 +00:00
my ( $ io_running ) = $ myrepl { 'Slave_IO_Running' }
// $ myrepl { 'Replica_IO_Running' } ;
2015-08-19 12:45:24 +00:00
debugprint "IO RUNNING: $io_running " ;
2022-06-23 12:31:46 +00:00
my ( $ sql_running ) = $ myrepl { 'Slave_SQL_Running' }
// $ myrepl { 'Replica_SQL_Running' } ;
2015-08-19 12:45:24 +00:00
debugprint "SQL RUNNING: $sql_running " ;
2022-06-15 13:17:55 +00:00
2022-06-23 12:31:46 +00:00
my ( $ seconds_behind_master ) = $ myrepl { 'Seconds_Behind_Master' }
// $ myrepl { 'Seconds_Behind_Source' } ;
2022-06-15 13:17:55 +00:00
$ seconds_behind_master = 1000000 unless defined ( $ seconds_behind_master ) ;
2015-08-19 12:45:24 +00:00
debugprint "SECONDS : $seconds_behind_master " ;
if ( defined ( $ io_running )
and ( $ io_running !~ /yes/i or $ sql_running !~ /yes/i ) )
{
badprint
2016-04-22 15:22:00 +00:00
"This replication slave is not running but seems to be configured." ;
2015-08-19 12:45:24 +00:00
}
2016-11-03 09:36:59 +00:00
if ( defined ( $ io_running )
2023-03-22 15:34:10 +00:00
&& $ io_running =~ /yes/i
2015-08-19 12:45:24 +00:00
&& $ sql_running =~ /yes/i )
{
if ( $ myvar { 'read_only' } eq 'OFF' ) {
badprint
"This replication slave is running with the read_only option disabled." ;
}
else {
goodprint
"This replication slave is running with the read_only option enabled." ;
}
if ( $ seconds_behind_master > 0 ) {
badprint
"This replication slave is lagging and slave has $seconds_behind_master second(s) behind master host." ;
}
else {
2015-12-10 10:52:39 +00:00
goodprint "This replication slave is up to date with master." ;
2015-08-19 12:45:24 +00:00
}
}
2009-09-17 23:13:22 +00:00
}
2022-02-07 22:57:45 +00:00
# https://endoflife.software/applications/databases/mysql
# https://endoflife.date/mariadb
2008-09-08 01:16:39 +00:00
sub validate_mysql_version {
2015-08-19 12:45:24 +00:00
( $ mysqlvermajor , $ mysqlverminor , $ mysqlvermicro ) =
$ myvar { 'version' } =~ /^(\d+)(?:\.(\d+)|)(?:\.(\d+)|)/ ;
$ mysqlverminor || = 0 ;
$ mysqlvermicro || = 0 ;
2019-09-25 21:29:22 +00:00
2023-03-27 16:33:49 +00:00
prettyprint " " ;
2021-02-05 14:25:09 +00:00
if ( mysql_version_eq ( 8 )
or mysql_version_eq ( 5 , 7 )
or mysql_version_eq ( 10 , 3 )
or mysql_version_eq ( 10 , 4 )
2021-07-13 16:56:52 +00:00
or mysql_version_eq ( 10 , 5 )
2022-02-07 22:57:45 +00:00
or mysql_version_eq ( 10 , 6 )
2022-06-15 13:11:34 +00:00
or mysql_version_eq ( 10 , 7 )
2022-09-26 12:12:37 +00:00
or mysql_version_eq ( 10 , 8 )
or mysql_version_eq ( 10 , 9 )
or mysql_version_eq ( 10 , 10 )
or mysql_version_eq ( 10 , 11 ) )
2019-09-25 21:29:22 +00:00
{
2021-02-05 14:25:09 +00:00
goodprint "Currently running supported MySQL version "
. $ myvar { 'version' } . "" ;
2019-09-25 21:29:22 +00:00
return ;
2022-06-23 12:31:46 +00:00
}
else {
2015-08-19 12:45:24 +00:00
badprint "Your MySQL version "
. $ myvar { 'version' }
2022-06-30 12:46:54 +00:00
. " is EOL software. Upgrade soon!" ;
2022-06-23 12:31:46 +00:00
push ( @ generalrec ,
2022-12-29 04:13:02 +00:00
"You are using an unsupported version for production environments"
) ;
2022-06-23 12:31:46 +00:00
push ( @ generalrec ,
"Upgrade as soon as possible to a supported version !" ) ;
2015-08-19 12:45:24 +00:00
}
2008-09-08 01:16:39 +00:00
}
2018-02-22 15:11:42 +00:00
# Checks if MySQL version is equal to (major, minor, micro)
sub mysql_version_eq {
my ( $ maj , $ min , $ mic ) = @ _ ;
2019-09-25 21:29:22 +00:00
my ( $ mysqlvermajor , $ mysqlverminor , $ mysqlvermicro ) =
$ myvar { 'version' } =~ /^(\d+)(?:\.(\d+)|)(?:\.(\d+)|)/ ;
2018-11-26 12:57:11 +00:00
return int ( $ mysqlvermajor ) == int ( $ maj )
if ( ! defined ( $ min ) && ! defined ( $ mic ) ) ;
return int ( $ mysqlvermajor ) == int ( $ maj ) && int ( $ mysqlverminor ) == int ( $ min )
if ( ! defined ( $ mic ) ) ;
2018-03-19 16:17:11 +00:00
return ( int ( $ mysqlvermajor ) == int ( $ maj )
&& int ( $ mysqlverminor ) == int ( $ min )
&& int ( $ mysqlvermicro ) == int ( $ mic ) ) ;
2018-02-22 15:11:42 +00:00
}
2018-03-19 16:17:11 +00:00
2015-07-15 14:58:18 +00:00
# Checks if MySQL version is greater than equal to (major, minor, micro)
2011-04-02 11:54:00 +00:00
sub mysql_version_ge {
2015-08-19 12:45:24 +00:00
my ( $ maj , $ min , $ mic ) = @ _ ;
$ min || = 0 ;
$ mic || = 0 ;
2019-09-25 21:29:22 +00:00
my ( $ mysqlvermajor , $ mysqlverminor , $ mysqlvermicro ) =
$ myvar { 'version' } =~ /^(\d+)(?:\.(\d+)|)(?:\.(\d+)|)/ ;
2016-08-31 08:30:20 +00:00
return
int ( $ mysqlvermajor ) > int ( $ maj )
|| ( int ( $ mysqlvermajor ) == int ( $ maj ) && int ( $ mysqlverminor ) > int ( $ min ) )
2017-07-05 09:51:33 +00:00
|| ( int ( $ mysqlvermajor ) == int ( $ maj )
&& int ( $ mysqlverminor ) == int ( $ min )
2016-08-31 08:30:20 +00:00
&& int ( $ mysqlvermicro ) >= int ( $ mic ) ) ;
2011-04-02 11:54:00 +00:00
}
2015-08-24 07:51:03 +00:00
# Checks if MySQL version is lower than equal to (major, minor, micro)
sub mysql_version_le {
my ( $ maj , $ min , $ mic ) = @ _ ;
$ min || = 0 ;
$ mic || = 0 ;
2019-09-25 21:29:22 +00:00
my ( $ mysqlvermajor , $ mysqlverminor , $ mysqlvermicro ) =
$ myvar { 'version' } =~ /^(\d+)(?:\.(\d+)|)(?:\.(\d+)|)/ ;
2016-08-31 08:30:20 +00:00
return
int ( $ mysqlvermajor ) < int ( $ maj )
|| ( int ( $ mysqlvermajor ) == int ( $ maj ) && int ( $ mysqlverminor ) < int ( $ min ) )
2017-07-05 09:51:33 +00:00
|| ( int ( $ mysqlvermajor ) == int ( $ maj )
&& int ( $ mysqlverminor ) == int ( $ min )
2016-08-31 08:30:20 +00:00
&& int ( $ mysqlvermicro ) <= int ( $ mic ) ) ;
2015-08-24 07:51:03 +00:00
}
2008-09-08 01:16:39 +00:00
# Checks for 32-bit boxes with more than 2GB of RAM
my ( $ arch ) ;
2015-08-19 12:45:24 +00:00
2008-09-08 01:16:39 +00:00
sub check_architecture {
2023-06-07 17:29:41 +00:00
if ( is_remote eq 1 ) {
infoprint "Skipping architecture check on remote host" ;
2023-06-22 13:15:25 +00:00
infoprint "Using default $opt{defaultarch} bits as target architecture" ;
$ arch = $ opt { defaultarch } ;
2023-06-07 17:29:41 +00:00
return ;
2023-06-07 16:22:02 +00:00
}
2015-08-19 12:45:24 +00:00
if ( `uname` =~ /SunOS/ && `isainfo -b` =~ /64/ ) {
$ arch = 64 ;
goodprint "Operating on 64-bit architecture" ;
}
2018-08-07 13:52:14 +00:00
elsif ( `uname` !~ /SunOS/ && `uname -m` =~ /(64|s390x)/ ) {
2015-08-19 12:45:24 +00:00
$ arch = 64 ;
goodprint "Operating on 64-bit architecture" ;
}
elsif ( `uname` =~ /AIX/ && `bootinfo -K` =~ /64/ ) {
$ arch = 64 ;
goodprint "Operating on 64-bit architecture" ;
}
elsif ( `uname` =~ /NetBSD|OpenBSD/ && `sysctl -b hw.machine` =~ /64/ ) {
$ arch = 64 ;
goodprint "Operating on 64-bit architecture" ;
}
elsif ( `uname` =~ /FreeBSD/ && `sysctl -b hw.machine_arch` =~ /64/ ) {
$ arch = 64 ;
goodprint "Operating on 64-bit architecture" ;
}
elsif ( `uname` =~ /Darwin/ && `uname -m` =~ /Power Macintosh/ ) {
# Darwin box.local 9.8.0 Darwin Kernel Version 9.8.0: Wed Jul 15 16:57:01 PDT 2009; root:xnu1228.15.4~1/RELEASE_PPC Power Macintosh
$ arch = 64 ;
goodprint "Operating on 64-bit architecture" ;
}
elsif ( `uname` =~ /Darwin/ && `uname -m` =~ /x86_64/ ) {
2023-09-26 20:50:57 +00:00
# Darwin gibas.local 12.3.2 Darwin Kernel Version 12.3.0: Sun Jan 6 22:37:10 PST 2013; root:xnu-2050.22.13~1/RELEASE_X86_64 x86_64
2015-08-19 12:45:24 +00:00
$ arch = 64 ;
goodprint "Operating on 64-bit architecture" ;
}
else {
$ arch = 32 ;
if ( $ physical_memory > 2147483648 ) {
badprint
"Switch to 64-bit OS - MySQL cannot currently use all of your RAM" ;
}
else {
2016-03-29 12:22:45 +00:00
goodprint "Operating on 32-bit architecture with less than 2GB RAM" ;
2015-08-19 12:45:24 +00:00
}
}
$ result { 'OS' } { 'Architecture' } = "$arch bits" ;
2016-03-22 13:44:01 +00:00
2008-09-08 01:16:39 +00:00
}
# Start up a ton of storage engine counts/statistics
2015-08-19 12:45:24 +00:00
my ( % enginestats , % enginecount , $ fragtables ) ;
2008-09-08 01:16:39 +00:00
sub check_storage_engines {
2019-09-25 21:50:15 +00:00
subheaderprint "Storage Engine Statistics" ;
2015-08-19 12:45:24 +00:00
if ( $ opt { skipsize } eq 1 ) {
infoprint "Skipped due to --skipsize option" ;
return ;
}
my $ engines ;
2016-03-16 17:40:44 +00:00
if ( mysql_version_ge ( 5 , 5 ) ) {
my @ engineresults = select_array
"SELECT ENGINE,SUPPORT FROM information_schema.ENGINES ORDER BY ENGINE ASC" ;
foreach my $ line ( @ engineresults ) {
my ( $ engine , $ engineenabled ) ;
( $ engine , $ engineenabled ) = $ line =~ /([a-zA-Z_]*)\s+([a-zA-Z]+)/ ;
$ result { 'Engine' } { $ engine } { 'Enabled' } = $ engineenabled ;
$ engines . =
( $ engineenabled eq "YES" || $ engineenabled eq "DEFAULT" )
? greenwrap "+" . $ engine . " "
: redwrap "-" . $ engine . " " ;
}
}
elsif ( mysql_version_ge ( 5 , 1 , 5 ) ) {
2015-08-19 12:45:24 +00:00
my @ engineresults = select_array
2023-03-16 14:03:34 +00:00
"SELECT ENGINE, SUPPORT FROM information_schema.ENGINES WHERE ENGINE NOT IN ('MyISAM', 'MERGE', 'MEMORY') ORDER BY ENGINE" ;
2015-08-19 12:45:24 +00:00
foreach my $ line ( @ engineresults ) {
my ( $ engine , $ engineenabled ) ;
( $ engine , $ engineenabled ) = $ line =~ /([a-zA-Z_]*)\s+([a-zA-Z]+)/ ;
$ result { 'Engine' } { $ engine } { 'Enabled' } = $ engineenabled ;
$ engines . =
( $ engineenabled eq "YES" || $ engineenabled eq "DEFAULT" )
? greenwrap "+" . $ engine . " "
: redwrap "-" . $ engine . " " ;
}
}
else {
$ engines . =
( defined $ myvar { 'have_archive' } && $ myvar { 'have_archive' } eq "YES" )
? greenwrap "+Archive "
: redwrap "-Archive " ;
$ engines . =
( defined $ myvar { 'have_bdb' } && $ myvar { 'have_bdb' } eq "YES" )
? greenwrap "+BDB "
: redwrap "-BDB " ;
$ engines . =
( defined $ myvar { 'have_federated_engine' }
&& $ myvar { 'have_federated_engine' } eq "YES" )
? greenwrap "+Federated "
: redwrap "-Federated " ;
$ engines . =
( defined $ myvar { 'have_innodb' } && $ myvar { 'have_innodb' } eq "YES" )
? greenwrap "+InnoDB "
: redwrap "-InnoDB " ;
$ engines . =
( defined $ myvar { 'have_isam' } && $ myvar { 'have_isam' } eq "YES" )
? greenwrap "+ISAM "
: redwrap "-ISAM " ;
$ engines . =
( defined $ myvar { 'have_ndbcluster' }
&& $ myvar { 'have_ndbcluster' } eq "YES" )
? greenwrap "+NDBCluster "
: redwrap "-NDBCluster " ;
}
2016-03-29 12:22:45 +00:00
my @ dblist = grep { $ _ ne 'lost+found' } select_array "SHOW DATABASES" ;
2015-09-02 13:40:57 +00:00
2015-08-19 12:45:24 +00:00
$ result { 'Databases' } { 'List' } = [ @ dblist ] ;
infoprint "Status: $engines" ;
if ( mysql_version_ge ( 5 , 1 , 5 ) ) {
2016-03-29 12:22:45 +00:00
2022-09-13 13:17:39 +00:00
# MySQL 5+ servers can have table sizes calculated quickly from information schema
2015-08-19 12:45:24 +00:00
my @ templist = select_array
2022-06-30 12:46:54 +00:00
"SELECT ENGINE, SUM(DATA_LENGTH+INDEX_LENGTH), COUNT(ENGINE), SUM(DATA_LENGTH), SUM(INDEX_LENGTH) FROM information_schema.TABLES WHERE TABLE_SCHEMA NOT IN ('information_schema', 'performance_schema', 'mysql') AND ENGINE IS NOT NULL GROUP BY ENGINE ORDER BY ENGINE ASC;" ;
2015-08-19 12:45:24 +00:00
my ( $ engine , $ size , $ count , $ dsize , $ isize ) ;
foreach my $ line ( @ templist ) {
( $ engine , $ size , $ count , $ dsize , $ isize ) =
2016-08-26 08:40:58 +00:00
$ line =~ /([a-zA-Z_]+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/ ;
debugprint "Engine Found: $engine" ;
2021-02-05 14:25:09 +00:00
next unless ( defined ( $ engine ) or trim ( $ engine ) eq '' ) ;
$ size = 0 unless ( defined ( $ size ) or trim ( $ engine ) eq '' ) ;
$ isize = 0 unless ( defined ( $ isize ) or trim ( $ engine ) eq '' ) ;
$ dsize = 0 unless ( defined ( $ dsize ) or trim ( $ engine ) eq '' ) ;
$ count = 0 unless ( defined ( $ count ) or trim ( $ engine ) eq '' ) ;
2015-08-19 12:45:24 +00:00
$ enginestats { $ engine } = $ size ;
$ enginecount { $ engine } = $ count ;
$ result { 'Engine' } { $ engine } { 'Table Number' } = $ count ;
$ result { 'Engine' } { $ engine } { 'Total Size' } = $ size ;
$ result { 'Engine' } { $ engine } { 'Data Size' } = $ dsize ;
$ result { 'Engine' } { $ engine } { 'Index Size' } = $ isize ;
}
2023-07-06 06:19:29 +00:00
2023-06-22 13:15:25 +00:00
#print Dumper( \%enginestats ) if $opt{debug};
2016-08-31 08:30:20 +00:00
my $ not_innodb = '' ;
2016-12-12 11:19:49 +00:00
if ( not defined $ result { 'Variables' } { 'innodb_file_per_table' } ) {
$ not_innodb = "AND NOT ENGINE='InnoDB'" ;
2017-02-07 05:56:17 +00:00
}
elsif ( $ result { 'Variables' } { 'innodb_file_per_table' } eq 'OFF' ) {
2016-08-31 08:30:20 +00:00
$ not_innodb = "AND NOT ENGINE='InnoDB'" ;
2016-06-02 07:23:46 +00:00
}
2015-08-19 12:45:24 +00:00
$ result { 'Tables' } { 'Fragmented tables' } =
[ select_array
2022-12-29 08:42:05 +00:00
"SELECT TABLE_SCHEMA, TABLE_NAME, ENGINE, CAST(DATA_FREE AS SIGNED) FROM information_schema.TABLES WHERE TABLE_SCHEMA NOT IN ('information_schema', 'performance_schema', 'mysql') AND DATA_LENGTH/1024/1024>100 AND cast(DATA_FREE as signed)*100/(DATA_LENGTH+INDEX_LENGTH+cast(DATA_FREE as signed)) > 10 AND NOT ENGINE='MEMORY' $not_innodb"
2015-08-19 12:45:24 +00:00
] ;
2016-08-31 08:30:20 +00:00
$ fragtables = scalar @ { $ result { 'Tables' } { 'Fragmented tables' } } ;
2015-08-19 12:45:24 +00:00
}
else {
# MySQL < 5 servers take a lot of work to get table sizes
my @ tblist ;
2016-03-29 12:22:45 +00:00
# Now we build a database list, and loop through it to get storage engine stats for tables
2015-08-19 12:45:24 +00:00
foreach my $ db ( @ dblist ) {
chomp ( $ db ) ;
2016-11-03 09:36:59 +00:00
if ( $ db eq "information_schema"
2015-08-19 12:45:24 +00:00
or $ db eq "performance_schema"
2015-11-23 07:08:25 +00:00
or $ db eq "mysql"
2015-09-02 12:13:49 +00:00
or $ db eq "lost+found" )
2015-08-19 12:45:24 +00:00
{
next ;
}
my @ ixs = ( 1 , 6 , 9 ) ;
if ( ! mysql_version_ge ( 4 , 1 ) ) {
# MySQL 3.23/4.0 keeps Data_Length in the 5th (0-based) column
@ ixs = ( 1 , 5 , 8 ) ;
}
push ( @ tblist ,
map { [ ( split ) [ @ ixs ] ] }
select_array "SHOW TABLE STATUS FROM \\\`$db\\\`" ) ;
}
# Parse through the table list to generate storage engine counts/statistics
$ fragtables = 0 ;
foreach my $ tbl ( @ tblist ) {
2021-10-15 11:56:27 +00:00
2023-06-22 13:15:25 +00:00
#debugprint "Data dump " . Dumper(@$tbl) if $opt{debug};
2015-08-19 12:45:24 +00:00
my ( $ engine , $ size , $ datafree ) = @$ tbl ;
2019-10-03 19:52:30 +00:00
next if $ engine eq 'NULL' or not defined ( $ engine ) ;
2021-02-05 14:25:09 +00:00
$ size = 0 if $ size eq 'NULL' or not defined ( $ size ) ;
2019-10-03 19:52:30 +00:00
$ datafree = 0 if $ datafree eq 'NULL' or not defined ( $ datafree ) ;
2015-08-19 12:45:24 +00:00
if ( defined $ enginestats { $ engine } ) {
$ enginestats { $ engine } += $ size ;
$ enginecount { $ engine } += 1 ;
}
else {
$ enginestats { $ engine } = $ size ;
$ enginecount { $ engine } = 1 ;
}
if ( $ datafree > 0 ) {
$ fragtables + + ;
}
}
}
while ( my ( $ engine , $ size ) = each ( % enginestats ) ) {
infoprint "Data in $engine tables: "
2018-07-05 14:48:45 +00:00
. hr_bytes ( $ size )
2015-08-19 12:45:24 +00:00
. " (Tables: "
. $ enginecount { $ engine } . ")" . "" ;
}
# If the storage engine isn't being used, recommend it to be disabled
if ( ! defined $ enginestats { 'InnoDB' }
&& defined $ myvar { 'have_innodb' }
&& $ myvar { 'have_innodb' } eq "YES" )
{
2023-03-27 16:12:52 +00:00
badprint "InnoDB is enabled, but isn't being used" ;
2015-08-19 12:45:24 +00:00
push ( @ generalrec ,
"Add skip-innodb to MySQL configuration to disable InnoDB" ) ;
}
if ( ! defined $ enginestats { 'BerkeleyDB' }
&& defined $ myvar { 'have_bdb' }
&& $ myvar { 'have_bdb' } eq "YES" )
{
2023-03-27 16:12:52 +00:00
badprint "BDB is enabled, but isn't being used" ;
2015-08-19 12:45:24 +00:00
push ( @ generalrec ,
"Add skip-bdb to MySQL configuration to disable BDB" ) ;
}
if ( ! defined $ enginestats { 'ISAM' }
&& defined $ myvar { 'have_isam' }
&& $ myvar { 'have_isam' } eq "YES" )
{
2023-03-27 16:12:52 +00:00
badprint "MyISAM is enabled, but isn't being used" ;
2015-08-19 12:45:24 +00:00
push ( @ generalrec ,
2022-12-29 04:13:02 +00:00
"Add skip-isam to MySQL configuration to disable MyISAM (MySQL > 4.1.0)"
2015-08-19 12:45:24 +00:00
) ;
}
# Fragmented tables
if ( $ fragtables > 0 ) {
badprint "Total fragmented tables: $fragtables" ;
2022-12-29 08:42:05 +00:00
push @ generalrec ,
2022-12-29 04:13:02 +00:00
'Run ALTER TABLE ... FORCE or OPTIMIZE TABLE to defragment tables for better performance' ;
2016-08-31 08:30:20 +00:00
my $ total_free = 0 ;
foreach my $ table_line ( @ { $ result { 'Tables' } { 'Fragmented tables' } } ) {
2022-12-29 08:42:05 +00:00
my ( $ table_schema , $ table_name , $ engine , $ data_free ) =
2022-12-29 04:13:02 +00:00
split /\t/msx , $ table_line ;
2016-08-31 08:30:20 +00:00
$ data_free = $ data_free / 1024 / 1024 ;
$ total_free += $ data_free ;
2022-12-29 08:42:05 +00:00
my $ generalrec ;
if ( $ engine eq 'InnoDB' ) {
2022-12-29 04:13:02 +00:00
$ generalrec =
" ALTER TABLE `$table_schema`.`$table_name` FORCE;" ;
}
else {
2022-12-29 08:42:05 +00:00
$ generalrec = " OPTIMIZE TABLE `$table_schema`.`$table_name`;" ;
}
$ generalrec . = " -- can free $data_free MiB" ;
push @ generalrec , $ generalrec ;
2016-06-02 07:23:46 +00:00
}
2022-12-29 08:42:05 +00:00
push @ generalrec ,
2023-03-27 16:12:52 +00:00
"Total freed space after defragmentation: $total_free MiB" ;
2015-08-19 12:45:24 +00:00
}
else {
goodprint "Total fragmented tables: $fragtables" ;
}
# Auto increments
my % tblist ;
# Find the maximum integer
my $ maxint = select_one "SELECT ~0" ;
$ result { 'MaxInt' } = $ maxint ;
# Now we use a database list, and loop through it to get storage engine stats for tables
foreach my $ db ( @ dblist ) {
chomp ( $ db ) ;
if ( ! $ tblist { $ db } ) {
$ tblist { $ db } = ( ) ;
}
if ( $ db eq "information_schema" ) { next ; }
my @ ia = ( 0 , 10 ) ;
if ( ! mysql_version_ge ( 4 , 1 ) ) {
# MySQL 3.23/4.0 keeps Data_Length in the 5th (0-based) column
@ ia = ( 0 , 9 ) ;
}
push (
@ { $ tblist { $ db } } ,
map { [ ( split ) [ @ ia ] ] }
select_array "SHOW TABLE STATUS FROM \\\`$db\\\`"
) ;
}
my @ dbnames = keys % tblist ;
foreach my $ db ( @ dbnames ) {
foreach my $ tbl ( @ { $ tblist { $ db } } ) {
my ( $ name , $ autoincrement ) = @$ tbl ;
if ( $ autoincrement =~ /^\d+?$/ ) {
my $ percent = percentage ( $ autoincrement , $ maxint ) ;
$ result { 'PctAutoIncrement' } { "$db.$name" } = $ percent ;
if ( $ percent >= 75 ) {
badprint
"Table '$db.$name' has an autoincrement value near max capacity ($percent%)" ;
}
}
}
}
2008-09-08 01:16:39 +00:00
}
my % mycalc ;
2015-08-19 12:45:24 +00:00
2023-06-22 19:45:07 +00:00
sub dump_into_file {
2023-07-06 06:19:29 +00:00
my $ file = shift ;
my $ content = shift ;
if ( - d "$opt{dumpdir}" ) {
$ file = "$opt{dumpdir}/$file" ;
open ( FILE , ">$file" ) or die "Can't open $file: $!" ;
2023-06-22 19:45:07 +00:00
print FILE $ content ;
close FILE ;
infoprint "Data saved to $file" ;
2023-07-06 06:19:29 +00:00
}
2023-06-22 19:45:07 +00:00
}
2023-07-06 06:19:29 +00:00
2008-09-08 01:16:39 +00:00
sub calculations {
2015-08-19 12:45:24 +00:00
if ( $ mystat { 'Questions' } < 1 ) {
2022-12-29 04:13:02 +00:00
badprint "Your server has not answered any queries: cannot continue..." ;
2015-08-24 08:00:10 +00:00
exit 2 ;
2015-08-19 12:45:24 +00:00
}
2023-04-25 21:05:47 +00:00
# Per-thread memory
2023-06-18 19:52:36 +00:00
$ mycalc { 'per_thread_buffers' } = 0 ;
2023-07-06 06:19:29 +00:00
$ mycalc { 'per_thread_buffers' } += $ myvar { 'read_buffer_size' }
if is_int ( $ myvar { 'read_buffer_size' } ) ;
$ mycalc { 'per_thread_buffers' } += $ myvar { 'read_rnd_buffer_size' }
if is_int ( $ myvar { 'read_rnd_buffer_size' } ) ;
$ mycalc { 'per_thread_buffers' } += $ myvar { 'sort_buffer_size' }
if is_int ( $ myvar { 'sort_buffer_size' } ) ;
$ mycalc { 'per_thread_buffers' } += $ myvar { 'thread_stack' }
if is_int ( $ myvar { 'thread_stack' } ) ;
$ mycalc { 'per_thread_buffers' } += $ myvar { 'join_buffer_size' }
if is_int ( $ myvar { 'join_buffer_size' } ) ;
$ mycalc { 'per_thread_buffers' } += $ myvar { 'binlog_cache_size' }
if is_int ( $ myvar { 'binlog_cache_size' } ) ;
debugprint "per_thread_buffers: $mycalc{'per_thread_buffers'} ("
. human_size ( $ mycalc { 'per_thread_buffers' } ) . " )" ;
# Error max_allowed_packet is not included in thread buffers size
#$mycalc{'per_thread_buffers'} += $myvar{'max_allowed_packet'} if is_int($myvar{'max_allowed_packet'});
2023-06-18 19:56:12 +00:00
2023-06-18 19:52:36 +00:00
# Total per-thread memory
2015-08-19 12:45:24 +00:00
$ mycalc { 'total_per_thread_buffers' } =
$ mycalc { 'per_thread_buffers' } * $ myvar { 'max_connections' } ;
2023-07-06 06:19:29 +00:00
2023-06-18 19:52:36 +00:00
# Max total per-thread memory reached
2015-08-19 12:45:24 +00:00
$ mycalc { 'max_total_per_thread_buffers' } =
$ mycalc { 'per_thread_buffers' } * $ mystat { 'Max_used_connections' } ;
# Server-wide memory
$ mycalc { 'max_tmp_table_size' } =
( $ myvar { 'tmp_table_size' } > $ myvar { 'max_heap_table_size' } )
? $ myvar { 'max_heap_table_size' }
: $ myvar { 'tmp_table_size' } ;
$ mycalc { 'server_buffers' } =
$ myvar { 'key_buffer_size' } + $ mycalc { 'max_tmp_table_size' } ;
$ mycalc { 'server_buffers' } +=
( defined $ myvar { 'innodb_buffer_pool_size' } )
? $ myvar { 'innodb_buffer_pool_size' }
: 0 ;
$ mycalc { 'server_buffers' } +=
( defined $ myvar { 'innodb_additional_mem_pool_size' } )
? $ myvar { 'innodb_additional_mem_pool_size' }
: 0 ;
$ mycalc { 'server_buffers' } +=
( defined $ myvar { 'innodb_log_buffer_size' } )
? $ myvar { 'innodb_log_buffer_size' }
: 0 ;
$ mycalc { 'server_buffers' } +=
( defined $ myvar { 'query_cache_size' } ) ? $ myvar { 'query_cache_size' } : 0 ;
$ mycalc { 'server_buffers' } +=
( defined $ myvar { 'aria_pagecache_buffer_size' } )
? $ myvar { 'aria_pagecache_buffer_size' }
: 0 ;
# Global memory
# Max used memory is memory used by MySQL based on Max_used_connections
2018-05-21 23:10:22 +00:00
# This is the max memory used theoretically calculated with the max concurrent connection number reached by mysql
2015-08-19 12:45:24 +00:00
$ mycalc { 'max_used_memory' } =
2016-04-19 14:19:31 +00:00
$ mycalc { 'server_buffers' } +
$ mycalc { "max_total_per_thread_buffers" } +
2018-08-06 09:53:02 +00:00
get_pf_memory ( ) ;
2018-11-26 12:57:11 +00:00
2018-08-06 09:53:02 +00:00
# + get_gcache_memory();
2015-08-19 12:45:24 +00:00
$ mycalc { 'pct_max_used_memory' } =
percentage ( $ mycalc { 'max_used_memory' } , $ physical_memory ) ;
# Total possible memory is memory needed by MySQL based on max_connections
2018-05-21 23:10:22 +00:00
# This is the max memory MySQL can theoretically used if all connections allowed has opened by mysql
2015-08-19 12:45:24 +00:00
$ mycalc { 'max_peak_memory' } =
2016-04-19 14:19:31 +00:00
$ mycalc { 'server_buffers' } +
$ mycalc { 'total_per_thread_buffers' } +
2018-08-06 09:53:02 +00:00
get_pf_memory ( ) ;
2018-11-26 12:57:11 +00:00
# + get_gcache_memory();
2015-08-19 12:45:24 +00:00
$ mycalc { 'pct_max_physical_memory' } =
percentage ( $ mycalc { 'max_peak_memory' } , $ physical_memory ) ;
debugprint "Max Used Memory: "
. hr_bytes ( $ mycalc { 'max_used_memory' } ) . "" ;
debugprint "Max Used Percentage RAM: "
. $ mycalc { 'pct_max_used_memory' } . "%" ;
debugprint "Max Peak Memory: "
. hr_bytes ( $ mycalc { 'max_peak_memory' } ) . "" ;
debugprint "Max Peak Percentage RAM: "
. $ mycalc { 'pct_max_physical_memory' } . "%" ;
2016-04-19 14:19:31 +00:00
2015-08-19 12:45:24 +00:00
# Slow queries
$ mycalc { 'pct_slow_queries' } =
int ( ( $ mystat { 'Slow_queries' } / $ mystat { 'Questions' } ) * 100 ) ;
# Connections
$ mycalc { 'pct_connections_used' } = int (
( $ mystat { 'Max_used_connections' } / $ myvar { 'max_connections' } ) * 100 ) ;
$ mycalc { 'pct_connections_used' } =
( $ mycalc { 'pct_connections_used' } > 100 )
? 100
: $ mycalc { 'pct_connections_used' } ;
# Aborted Connections
$ mycalc { 'pct_connections_aborted' } =
percentage ( $ mystat { 'Aborted_connects' } , $ mystat { 'Connections' } ) ;
debugprint "Aborted_connects: " . $ mystat { 'Aborted_connects' } . "" ;
debugprint "Connections: " . $ mystat { 'Connections' } . "" ;
debugprint "pct_connections_aborted: "
. $ mycalc { 'pct_connections_aborted' } . "" ;
# Key buffers
if ( mysql_version_ge ( 4 , 1 ) && $ myvar { 'key_buffer_size' } > 0 ) {
$ mycalc { 'pct_key_buffer_used' } = sprintf (
"%.1f" ,
(
1 - (
(
$ mystat { 'Key_blocks_unused' } *
$ myvar { 'key_cache_block_size' }
) / $ myvar { 'key_buffer_size' }
)
2018-11-26 12:57:11 +00:00
) * 100
2015-08-19 12:45:24 +00:00
) ;
}
else {
$ mycalc { 'pct_key_buffer_used' } = 0 ;
}
if ( $ mystat { 'Key_read_requests' } > 0 ) {
$ mycalc { 'pct_keys_from_mem' } = sprintf (
"%.1f" ,
(
100 - (
( $ mystat { 'Key_reads' } / $ mystat { 'Key_read_requests' } ) *
100
)
)
) ;
}
else {
$ mycalc { 'pct_keys_from_mem' } = 0 ;
}
if ( defined $ mystat { 'Aria_pagecache_read_requests' }
&& $ mystat { 'Aria_pagecache_read_requests' } > 0 )
{
$ mycalc { 'pct_aria_keys_from_mem' } = sprintf (
"%.1f" ,
(
100 - (
(
$ mystat { 'Aria_pagecache_reads' } /
$ mystat { 'Aria_pagecache_read_requests' }
) * 100
)
)
) ;
}
else {
$ mycalc { 'pct_aria_keys_from_mem' } = 0 ;
}
if ( $ mystat { 'Key_write_requests' } > 0 ) {
2017-07-05 09:51:33 +00:00
$ mycalc { 'pct_wkeys_from_mem' } = sprintf ( "%.1f" ,
( ( $ mystat { 'Key_writes' } / $ mystat { 'Key_write_requests' } ) * 100 )
) ;
2015-08-19 12:45:24 +00:00
}
else {
$ mycalc { 'pct_wkeys_from_mem' } = 0 ;
}
if ( $ doremote eq 0 and ! mysql_version_ge ( 5 ) ) {
my $ size = 0 ;
$ size += ( split ) [ 0 ]
for
2021-01-27 04:09:41 +00:00
`find "$myvar{'datadir'}" -name "*.MYI" -print0 2>&1 | xargs $xargsflags -0 du -L $duflags 2>&1` ;
2015-08-19 12:45:24 +00:00
$ mycalc { 'total_myisam_indexes' } = $ size ;
2021-01-27 04:09:41 +00:00
$ size = 0 + ( split ) [ 0 ]
for
`find "$myvar{'datadir'}" -name "*.MAI" -print0 2>&1 | xargs $xargsflags -0 du -L $duflags 2>&1` ;
2021-02-05 14:25:09 +00:00
$ mycalc { 'total_aria_indexes' } = $ size ;
2015-08-19 12:45:24 +00:00
}
elsif ( mysql_version_ge ( 5 ) ) {
$ mycalc { 'total_myisam_indexes' } = select_one
2022-06-30 12:46:54 +00:00
"SELECT IFNULL(SUM(INDEX_LENGTH), 0) FROM information_schema.TABLES WHERE TABLE_SCHEMA NOT IN ('information_schema') AND ENGINE = 'MyISAM';" ;
2015-10-09 09:14:39 +00:00
$ mycalc { 'total_aria_indexes' } = select_one
2022-06-30 12:46:54 +00:00
"SELECT IFNULL(SUM(INDEX_LENGTH), 0) FROM information_schema.TABLES WHERE TABLE_SCHEMA NOT IN ('information_schema') AND ENGINE = 'Aria';" ;
2015-08-19 12:45:24 +00:00
}
2021-01-27 04:09:41 +00:00
if ( defined $ mycalc { 'total_myisam_indexes' } ) {
2015-08-19 12:45:24 +00:00
chomp ( $ mycalc { 'total_myisam_indexes' } ) ;
}
2021-01-27 04:09:41 +00:00
if ( defined $ mycalc { 'total_aria_indexes' } ) {
2015-08-19 12:45:24 +00:00
chomp ( $ mycalc { 'total_aria_indexes' } ) ;
}
# Query cache
2018-06-29 12:06:42 +00:00
if ( mysql_version_ge ( 8 ) and mysql_version_le ( 10 ) ) {
$ mycalc { 'query_cache_efficiency' } = 0 ;
2018-11-26 12:57:11 +00:00
}
elsif ( mysql_version_ge ( 4 ) ) {
2015-08-19 12:45:24 +00:00
$ mycalc { 'query_cache_efficiency' } = sprintf (
"%.1f" ,
(
$ mystat { 'Qcache_hits' } /
( $ mystat { 'Com_select' } + $ mystat { 'Qcache_hits' } )
2018-11-26 12:57:11 +00:00
) * 100
2015-08-19 12:45:24 +00:00
) ;
if ( $ myvar { 'query_cache_size' } ) {
$ mycalc { 'pct_query_cache_used' } = sprintf (
"%.1f" ,
100 - (
$ mystat { 'Qcache_free_memory' } / $ myvar { 'query_cache_size' }
2018-11-26 12:57:11 +00:00
) * 100
2015-08-19 12:45:24 +00:00
) ;
}
if ( $ mystat { 'Qcache_lowmem_prunes' } == 0 ) {
$ mycalc { 'query_cache_prunes_per_day' } = 0 ;
}
else {
$ mycalc { 'query_cache_prunes_per_day' } = int (
$ mystat { 'Qcache_lowmem_prunes' } / ( $mystat{'Uptime'} / 86400 )
) ;
}
}
# Sorting
$ mycalc { 'total_sorts' } = $ mystat { 'Sort_scan' } + $ mystat { 'Sort_range' } ;
if ( $ mycalc { 'total_sorts' } > 0 ) {
$ mycalc { 'pct_temp_sort_table' } = int (
( $ mystat { 'Sort_merge_passes' } / $ mycalc { 'total_sorts' } ) * 100 ) ;
}
# Joins
$ mycalc { 'joins_without_indexes' } =
$ mystat { 'Select_range_check' } + $ mystat { 'Select_full_join' } ;
$ mycalc { 'joins_without_indexes_per_day' } =
int ( $ mycalc { 'joins_without_indexes' } / ( $mystat{'Uptime'} / 86400 ) ) ;
# Temporary tables
if ( $ mystat { 'Created_tmp_tables' } > 0 ) {
if ( $ mystat { 'Created_tmp_disk_tables' } > 0 ) {
$ mycalc { 'pct_temp_disk' } = int (
(
$ mystat { 'Created_tmp_disk_tables' } /
$ mystat { 'Created_tmp_tables' }
) * 100
) ;
}
else {
$ mycalc { 'pct_temp_disk' } = 0 ;
}
}
# Table cache
if ( $ mystat { 'Opened_tables' } > 0 ) {
2021-08-25 10:01:28 +00:00
if ( not defined ( $ mystat { 'Table_open_cache_hits' } ) ) {
$ mycalc { 'table_cache_hit_rate' } =
int ( $ mystat { 'Open_tables' } * 100 / $ mystat { 'Opened_tables' } ) ;
}
else {
$ mycalc { 'table_cache_hit_rate' } = int (
$ mystat { 'Table_open_cache_hits' } * 100 / (
$ mystat { 'Table_open_cache_hits' } +
$ mystat { 'Table_open_cache_misses' }
)
) ;
}
}
else {
2015-08-19 12:45:24 +00:00
$ mycalc { 'table_cache_hit_rate' } = 100 ;
}
# Open files
if ( $ myvar { 'open_files_limit' } > 0 ) {
$ mycalc { 'pct_files_open' } =
int ( $ mystat { 'Open_files' } * 100 / $ myvar { 'open_files_limit' } ) ;
}
# Table locks
if ( $ mystat { 'Table_locks_immediate' } > 0 ) {
if ( $ mystat { 'Table_locks_waited' } == 0 ) {
$ mycalc { 'pct_table_locks_immediate' } = 100 ;
}
else {
$ mycalc { 'pct_table_locks_immediate' } = int (
$ mystat { 'Table_locks_immediate' } * 100 / (
$ mystat { 'Table_locks_waited' } +
$ mystat { 'Table_locks_immediate' }
)
) ;
}
}
# Thread cache
$ mycalc { 'thread_cache_hit_rate' } =
int ( 100 -
( ( $ mystat { 'Threads_created' } / $ mystat { 'Connections' } ) * 100 ) ) ;
# Other
if ( $ mystat { 'Connections' } > 0 ) {
$ mycalc { 'pct_aborted_connections' } =
int ( ( $ mystat { 'Aborted_connects' } / $ mystat { 'Connections' } ) * 100 ) ;
}
if ( $ mystat { 'Questions' } > 0 ) {
$ mycalc { 'total_reads' } = $ mystat { 'Com_select' } ;
$ mycalc { 'total_writes' } =
$ mystat { 'Com_delete' } +
$ mystat { 'Com_insert' } +
$ mystat { 'Com_update' } +
$ mystat { 'Com_replace' } ;
if ( $ mycalc { 'total_reads' } == 0 ) {
$ mycalc { 'pct_reads' } = 0 ;
$ mycalc { 'pct_writes' } = 100 ;
}
else {
$ mycalc { 'pct_reads' } = int (
(
$ mycalc { 'total_reads' } /
( $ mycalc { 'total_reads' } + $ mycalc { 'total_writes' } )
) * 100
) ;
$ mycalc { 'pct_writes' } = 100 - $ mycalc { 'pct_reads' } ;
}
}
# InnoDB
2021-08-25 10:01:28 +00:00
$ myvar { 'innodb_log_files_in_group' } = 1
unless defined ( $ myvar { 'innodb_log_files_in_group' } ) ;
2023-07-06 06:19:29 +00:00
$ myvar { 'innodb_log_files_in_group' } = 1
if $ myvar { 'innodb_log_files_in_group' } == 0 ;
2023-06-22 08:10:56 +00:00
2021-08-25 10:01:28 +00:00
$ myvar { "innodb_buffer_pool_instances" } = 1
unless defined ( $ myvar { 'innodb_buffer_pool_instances' } ) ;
2015-08-19 12:45:24 +00:00
if ( $ myvar { 'have_innodb' } eq "YES" ) {
$ mycalc { 'innodb_log_size_pct' } =
2017-02-07 05:56:17 +00:00
( $ myvar { 'innodb_log_file_size' } *
$ myvar { 'innodb_log_files_in_group' } * 100 /
2015-08-19 12:45:24 +00:00
$ myvar { 'innodb_buffer_pool_size' } ) ;
}
2021-02-05 14:25:09 +00:00
if ( ! defined $ myvar { 'innodb_buffer_pool_size' } ) {
$ mycalc { 'innodb_log_size_pct' } = 0 ;
$ myvar { 'innodb_buffer_pool_size' } = 0 ;
2019-10-01 23:13:34 +00:00
}
2021-02-05 14:25:09 +00:00
2018-02-18 04:44:13 +00:00
# InnoDB Buffer pool read cache efficiency
2015-08-19 12:45:24 +00:00
(
$ mystat { 'Innodb_buffer_pool_read_requests' } ,
$ mystat { 'Innodb_buffer_pool_reads' }
)
= ( 1 , 1 )
unless defined $ mystat { 'Innodb_buffer_pool_reads' } ;
$ mycalc { 'pct_read_efficiency' } = percentage (
(
$ mystat { 'Innodb_buffer_pool_read_requests' } -
$ mystat { 'Innodb_buffer_pool_reads' }
) ,
$ mystat { 'Innodb_buffer_pool_read_requests' }
) if defined $ mystat { 'Innodb_buffer_pool_read_requests' } ;
debugprint "pct_read_efficiency: " . $ mycalc { 'pct_read_efficiency' } . "" ;
debugprint "Innodb_buffer_pool_reads: "
. $ mystat { 'Innodb_buffer_pool_reads' } . "" ;
debugprint "Innodb_buffer_pool_read_requests: "
. $ mystat { 'Innodb_buffer_pool_read_requests' } . "" ;
2016-02-24 19:20:48 +00:00
2018-02-18 04:44:13 +00:00
# InnoDB log write cache efficiency
2016-03-29 12:22:45 +00:00
( $ mystat { 'Innodb_log_write_requests' } , $ mystat { 'Innodb_log_writes' } ) =
( 1 , 1 )
2016-02-24 19:20:48 +00:00
unless defined $ mystat { 'Innodb_log_writes' } ;
2015-08-19 12:45:24 +00:00
$ mycalc { 'pct_write_efficiency' } = percentage (
2016-03-29 12:22:45 +00:00
( $ mystat { 'Innodb_log_write_requests' } - $ mystat { 'Innodb_log_writes' } ) ,
2016-02-24 19:20:48 +00:00
$ mystat { 'Innodb_log_write_requests' }
) if defined $ mystat { 'Innodb_log_write_requests' } ;
debugprint "pct_write_efficiency: " . $ mycalc { 'pct_write_efficiency' } . "" ;
2016-03-29 12:22:45 +00:00
debugprint "Innodb_log_writes: " . $ mystat { 'Innodb_log_writes' } . "" ;
2016-02-24 19:20:48 +00:00
debugprint "Innodb_log_write_requests: "
. $ mystat { 'Innodb_log_write_requests' } . "" ;
2015-08-19 12:45:24 +00:00
$ mycalc { 'pct_innodb_buffer_used' } = percentage (
(
$ mystat { 'Innodb_buffer_pool_pages_total' } -
$ mystat { 'Innodb_buffer_pool_pages_free' }
) ,
$ mystat { 'Innodb_buffer_pool_pages_total' }
) if defined $ mystat { 'Innodb_buffer_pool_pages_total' } ;
# Binlog Cache
if ( $ myvar { 'log_bin' } ne 'OFF' ) {
$ mycalc { 'pct_binlog_cache' } = percentage (
$ mystat { 'Binlog_cache_use' } - $ mystat { 'Binlog_cache_disk_use' } ,
$ mystat { 'Binlog_cache_use' } ) ;
}
2008-09-08 01:16:39 +00:00
}
sub mysql_stats {
2016-04-11 10:01:01 +00:00
subheaderprint "Performance Metrics" ;
2015-08-19 12:45:24 +00:00
# Show uptime, queries per second, connections, traffic stats
my $ qps ;
if ( $ mystat { 'Uptime' } > 0 ) {
$ qps = sprintf ( "%.3f" , $ mystat { 'Questions' } / $ mystat { 'Uptime' } ) ;
}
push ( @ generalrec ,
2022-09-13 13:17:39 +00:00
"MySQL was started within the last 24 hours: recommendations may be inaccurate"
2015-08-19 12:45:24 +00:00
) if ( $ mystat { 'Uptime' } < 86400 ) ;
infoprint "Up for: "
. pretty_uptime ( $ mystat { 'Uptime' } ) . " ("
. hr_num ( $ mystat { 'Questions' } ) . " q ["
. hr_num ( $ qps )
. " qps], "
. hr_num ( $ mystat { 'Connections' } )
. " conn," . " TX: "
2016-03-02 15:12:38 +00:00
. hr_bytes_rnd ( $ mystat { 'Bytes_sent' } )
2015-08-19 12:45:24 +00:00
. ", RX: "
2016-03-02 15:12:38 +00:00
. hr_bytes_rnd ( $ mystat { 'Bytes_received' } ) . ")" ;
2015-08-19 12:45:24 +00:00
infoprint "Reads / Writes: "
. $ mycalc { 'pct_reads' } . "% / "
. $ mycalc { 'pct_writes' } . "%" ;
# Binlog Cache
if ( $ myvar { 'log_bin' } eq 'OFF' ) {
infoprint "Binary logging is disabled" ;
}
else {
infoprint "Binary logging is enabled (GTID MODE: "
. ( defined ( $ myvar { 'gtid_mode' } ) ? $ myvar { 'gtid_mode' } : "OFF" )
. ")" ;
}
# Memory usage
2016-04-19 14:19:31 +00:00
infoprint "Physical Memory : " . hr_bytes ( $ physical_memory ) ;
infoprint "Max MySQL memory : " . hr_bytes ( $ mycalc { 'max_peak_memory' } ) ;
infoprint "Other process memory: " . hr_bytes ( get_other_process_memory ( ) ) ;
2016-04-15 10:33:05 +00:00
2015-08-19 12:45:24 +00:00
infoprint "Total buffers: "
. hr_bytes ( $ mycalc { 'server_buffers' } )
. " global + "
. hr_bytes ( $ mycalc { 'per_thread_buffers' } )
. " per thread ($myvar{'max_connections'} max threads)" ;
2022-12-29 04:13:02 +00:00
infoprint "Performance_schema Max memory usage: "
. hr_bytes_rnd ( get_pf_memory ( ) ) ;
2022-09-13 13:17:39 +00:00
$ result { 'Performance_schema' } { 'memory' } = get_pf_memory ( ) ;
$ result { 'Performance_schema' } { 'pretty_memory' } =
2018-11-26 12:57:11 +00:00
hr_bytes_rnd ( get_pf_memory ( ) ) ;
2016-04-19 14:19:31 +00:00
infoprint "Galera GCache Max memory usage: "
. hr_bytes_rnd ( get_gcache_memory ( ) ) ;
2016-08-31 08:30:20 +00:00
$ result { 'Galera' } { 'GCache' } { 'memory' } = get_gcache_memory ( ) ;
$ result { 'Galera' } { 'GCache' } { 'pretty_memory' } =
hr_bytes_rnd ( get_gcache_memory ( ) ) ;
2015-08-19 12:45:24 +00:00
if ( $ opt { buffers } ne 0 ) {
infoprint "Global Buffers" ;
infoprint " +-- Key Buffer: "
. hr_bytes ( $ myvar { 'key_buffer_size' } ) . "" ;
infoprint " +-- Max Tmp Table: "
. hr_bytes ( $ mycalc { 'max_tmp_table_size' } ) . "" ;
if ( defined $ myvar { 'query_cache_type' } ) {
infoprint "Query Cache Buffers" ;
2018-11-26 12:57:11 +00:00
infoprint " +-- Query Cache: "
2015-08-19 12:45:24 +00:00
. $ myvar { 'query_cache_type' } . " - "
. (
$ myvar { 'query_cache_type' } eq 0 |
$ myvar { 'query_cache_type' } eq 'OFF' ? "DISABLED"
2016-03-29 12:22:45 +00:00
: (
$ myvar { 'query_cache_type' } eq 1 ? "ALL REQUESTS"
: "ON DEMAND"
)
2015-08-19 12:45:24 +00:00
) . "" ;
infoprint " +-- Query Cache Size: "
. hr_bytes ( $ myvar { 'query_cache_size' } ) . "" ;
}
infoprint "Per Thread Buffers" ;
infoprint " +-- Read Buffer: "
. hr_bytes ( $ myvar { 'read_buffer_size' } ) . "" ;
infoprint " +-- Read RND Buffer: "
. hr_bytes ( $ myvar { 'read_rnd_buffer_size' } ) . "" ;
infoprint " +-- Sort Buffer: "
. hr_bytes ( $ myvar { 'sort_buffer_size' } ) . "" ;
infoprint " +-- Thread stack: "
. hr_bytes ( $ myvar { 'thread_stack' } ) . "" ;
infoprint " +-- Join Buffer: "
. hr_bytes ( $ myvar { 'join_buffer_size' } ) . "" ;
if ( $ myvar { 'log_bin' } ne 'OFF' ) {
infoprint "Binlog Cache Buffers" ;
infoprint " +-- Binlog Cache: "
. hr_bytes ( $ myvar { 'binlog_cache_size' } ) . "" ;
}
}
2016-11-03 09:36:59 +00:00
if ( $ arch
2015-08-19 12:45:24 +00:00
&& $ arch == 32
&& $ mycalc { 'max_used_memory' } > 2 * 1024 * 1024 * 1024 )
{
badprint
2016-03-29 12:22:45 +00:00
"Allocating > 2GB RAM on 32-bit systems can cause system instability" ;
2015-08-19 12:45:24 +00:00
badprint "Maximum reached memory usage: "
. hr_bytes ( $ mycalc { 'max_used_memory' } )
. " ($mycalc{'pct_max_used_memory'}% of installed RAM)" ;
}
elsif ( $ mycalc { 'pct_max_used_memory' } > 85 ) {
badprint "Maximum reached memory usage: "
. hr_bytes ( $ mycalc { 'max_used_memory' } )
. " ($mycalc{'pct_max_used_memory'}% of installed RAM)" ;
}
else {
goodprint "Maximum reached memory usage: "
. hr_bytes ( $ mycalc { 'max_used_memory' } )
. " ($mycalc{'pct_max_used_memory'}% of installed RAM)" ;
}
if ( $ mycalc { 'pct_max_physical_memory' } > 85 ) {
badprint "Maximum possible memory usage: "
. hr_bytes ( $ mycalc { 'max_peak_memory' } )
. " ($mycalc{'pct_max_physical_memory'}% of installed RAM)" ;
push ( @ generalrec ,
"Reduce your overall MySQL memory footprint for system stability" ) ;
}
else {
goodprint "Maximum possible memory usage: "
. hr_bytes ( $ mycalc { 'max_peak_memory' } )
. " ($mycalc{'pct_max_physical_memory'}% of installed RAM)" ;
}
2016-04-19 14:19:31 +00:00
if ( $ physical_memory <
( $ mycalc { 'max_peak_memory' } + get_other_process_memory ( ) ) )
{
badprint
"Overall possible memory usage with other process exceeded memory" ;
push ( @ generalrec ,
2016-06-16 08:33:03 +00:00
"Dedicate this server to your database for highest performance." ) ;
2016-04-19 14:19:31 +00:00
}
else {
goodprint
"Overall possible memory usage with other process is compatible with memory available" ;
}
2016-04-15 10:33:05 +00:00
2015-08-19 12:45:24 +00:00
# Slow queries
if ( $ mycalc { 'pct_slow_queries' } > 5 ) {
badprint "Slow queries: $mycalc{'pct_slow_queries'}% ("
. hr_num ( $ mystat { 'Slow_queries' } ) . "/"
. hr_num ( $ mystat { 'Questions' } ) . ")" ;
}
else {
goodprint "Slow queries: $mycalc{'pct_slow_queries'}% ("
. hr_num ( $ mystat { 'Slow_queries' } ) . "/"
. hr_num ( $ mystat { 'Questions' } ) . ")" ;
}
if ( $ myvar { 'long_query_time' } > 10 ) {
push ( @ adjvars , "long_query_time (<= 10)" ) ;
}
if ( defined ( $ myvar { 'log_slow_queries' } ) ) {
if ( $ myvar { 'log_slow_queries' } eq "OFF" ) {
push ( @ generalrec ,
"Enable the slow query log to troubleshoot bad queries" ) ;
}
}
# Connections
if ( $ mycalc { 'pct_connections_used' } > 85 ) {
badprint
2022-09-13 13:17:39 +00:00
"Highest connection usage: $mycalc{'pct_connections_used'}% ($mystat{'Max_used_connections'}/$myvar{'max_connections'})" ;
2015-08-19 12:45:24 +00:00
push ( @ adjvars ,
"max_connections (> " . $ myvar { 'max_connections' } . ")" ) ;
push ( @ adjvars ,
"wait_timeout (< " . $ myvar { 'wait_timeout' } . ")" ,
"interactive_timeout (< " . $ myvar { 'interactive_timeout' } . ")" ) ;
push ( @ generalrec ,
"Reduce or eliminate persistent connections to reduce connection usage"
) ;
}
else {
goodprint
"Highest usage of available connections: $mycalc{'pct_connections_used'}% ($mystat{'Max_used_connections'}/$myvar{'max_connections'})" ;
}
# Aborted Connections
if ( $ mycalc { 'pct_connections_aborted' } > 3 ) {
badprint
2022-09-13 13:17:39 +00:00
"Aborted connections: $mycalc{'pct_connections_aborted'}% ($mystat{'Aborted_connects'}/$mystat{'Connections'})" ;
2015-08-19 12:45:24 +00:00
push ( @ generalrec ,
"Reduce or eliminate unclosed connections and network issues" ) ;
}
else {
goodprint
2022-09-13 13:17:39 +00:00
"Aborted connections: $mycalc{'pct_connections_aborted'}% ($mystat{'Aborted_connects'}/$mystat{'Connections'})" ;
2015-08-19 12:45:24 +00:00
}
2016-06-03 06:33:02 +00:00
# name resolution
2023-07-06 06:19:29 +00:00
debugprint "skip name resolve: $result{'Variables'}{'skip_name_resolve'}"
if ( defined ( $ result { 'Variables' } { 'skip_name_resolve' } ) ) ;
2017-03-06 14:17:43 +00:00
if ( defined ( $ result { 'Variables' } { 'skip_networking' } )
&& $ result { 'Variables' } { 'skip_networking' } eq 'ON' )
{
2017-02-08 17:10:48 +00:00
infoprint
"Skipped name resolution test due to skip_networking=ON in system variables." ;
}
elsif ( not defined ( $ result { 'Variables' } { 'skip_name_resolve' } ) ) {
2016-08-31 08:30:20 +00:00
infoprint
2016-09-12 12:18:14 +00:00
"Skipped name resolution test due to missing skip_name_resolve in system variables." ;
2016-08-31 08:30:20 +00:00
}
2022-06-23 12:31:46 +00:00
2022-03-12 18:13:32 +00:00
#Cpanel and Skip name resolve
2022-06-23 12:31:46 +00:00
elsif ( - r "/usr/local/cpanel/cpanel" ) {
if ( $ result { 'Variables' } { 'skip_name_resolve' } ne 'OFF' ) {
2022-03-12 18:14:52 +00:00
infoprint "CPanel and Flex system skip-name-resolve should be on" ;
}
2022-06-23 12:31:46 +00:00
if ( $ result { 'Variables' } { 'skip_name_resolve' } eq 'OFF' ) {
2022-03-12 18:13:32 +00:00
badprint "CPanel and Flex system skip-name-resolve should be on" ;
2022-06-23 12:31:46 +00:00
push ( @ generalrec ,
"name resolution is enabled due to cPanel doesn't support this disabled."
) ;
push ( @ adjvars , "skip-name-resolve=0" ) ;
2022-03-12 18:13:32 +00:00
}
2022-03-12 18:10:25 +00:00
}
2023-06-17 16:11:00 +00:00
elsif ( $ result { 'Variables' } { 'skip_name_resolve' } ne 'ON'
and $ result { 'Variables' } { 'skip_name_resolve' } ne '1' )
2023-06-07 17:29:41 +00:00
{
2016-06-03 06:33:02 +00:00
badprint
2022-06-30 12:46:54 +00:00
"Name resolution is active: a reverse name resolution is made for each new connection which can reduce performance" ;
2016-06-03 06:33:02 +00:00
push ( @ generalrec ,
2023-07-06 05:05:26 +00:00
"Configure your accounts with ip or subnets only, then update your configuration with skip-name-resolve=ON"
2016-08-31 08:30:20 +00:00
) ;
2023-07-06 05:05:26 +00:00
push ( @ adjvars , "skip-name-resolve=ON" ) ;
2016-06-03 06:33:02 +00:00
}
2015-08-19 12:45:24 +00:00
# Query cache
if ( ! mysql_version_ge ( 4 ) ) {
2018-11-26 12:57:11 +00:00
2015-08-19 12:45:24 +00:00
# MySQL versions < 4.01 don't support query caching
push ( @ generalrec ,
"Upgrade MySQL to version 4+ to utilize query caching" ) ;
}
2018-11-26 12:57:11 +00:00
elsif ( mysql_version_eq ( 8 ) ) {
2022-06-22 16:36:34 +00:00
infoprint "Query cache has been removed since MySQL 8.0" ;
2018-11-26 12:57:11 +00:00
2018-09-23 07:45:25 +00:00
#return;
}
2021-02-05 14:25:09 +00:00
elsif ( $ myvar { 'query_cache_size' } < 1
2021-01-27 06:02:56 +00:00
or $ myvar { 'query_cache_type' } eq "OFF" )
2017-02-07 05:56:17 +00:00
{
2016-12-08 08:45:38 +00:00
goodprint
2017-02-07 05:56:17 +00:00
"Query cache is disabled by default due to mutex contention on multiprocessor machines." ;
2016-03-16 15:53:30 +00:00
}
2015-08-19 12:45:24 +00:00
elsif ( $ mystat { 'Com_select' } == 0 ) {
badprint
2022-10-05 08:16:42 +00:00
"Query cache cannot be analyzed: no SELECT statements executed" ;
2015-08-19 12:45:24 +00:00
}
else {
if ( $ mycalc { 'query_cache_efficiency' } < 20 ) {
badprint
"Query cache efficiency: $mycalc{'query_cache_efficiency'}% ("
. hr_num ( $ mystat { 'Qcache_hits' } )
. " cached / "
. hr_num ( $ mystat { 'Qcache_hits' } + $ mystat { 'Com_select' } )
. " selects)" ;
push ( @ adjvars ,
"query_cache_limit (> "
. hr_bytes_rnd ( $ myvar { 'query_cache_limit' } )
. ", or use smaller result sets)" ) ;
2023-06-07 17:29:41 +00:00
badprint
"Query cache may be disabled by default due to mutex contention." ;
2023-06-07 16:45:22 +00:00
push ( @ adjvars , "query_cache_size (=0)" ) ;
push ( @ adjvars , "query_cache_type (=0)" ) ;
2023-06-07 17:29:41 +00:00
}
else {
goodprint
"Query cache efficiency: $mycalc{'query_cache_efficiency'}% ("
. hr_num ( $ mystat { 'Qcache_hits' } )
. " cached / "
. hr_num ( $ mystat { 'Qcache_hits' } + $ mystat { 'Com_select' } )
. " selects)" ;
if ( $ mycalc { 'query_cache_prunes_per_day' } > 98 ) {
badprint
"Query cache prunes per day: $mycalc{'query_cache_prunes_per_day'}" ;
if ( $ myvar { 'query_cache_size' } >= 128 * 1024 * 1024 ) {
push ( @ generalrec ,
"Increasing the query_cache size over 128M may reduce performance"
) ;
push ( @ adjvars ,
"query_cache_size (> "
. hr_bytes_rnd ( $ myvar { 'query_cache_size' } )
. ") [see warning above]" ) ;
}
else {
push ( @ adjvars ,
"query_cache_size (> "
. hr_bytes_rnd ( $ myvar { 'query_cache_size' } )
. ")" ) ;
}
}
else {
goodprint
"Query cache prunes per day: $mycalc{'query_cache_prunes_per_day'}" ;
}
}
2023-06-07 16:45:22 +00:00
2015-08-19 12:45:24 +00:00
}
# Sorting
if ( $ mycalc { 'total_sorts' } == 0 ) {
2016-04-19 14:19:31 +00:00
goodprint "No Sort requiring temporary tables" ;
2015-08-19 12:45:24 +00:00
}
elsif ( $ mycalc { 'pct_temp_sort_table' } > 10 ) {
badprint
"Sorts requiring temporary tables: $mycalc{'pct_temp_sort_table'}% ("
. hr_num ( $ mystat { 'Sort_merge_passes' } )
. " temp sorts / "
. hr_num ( $ mycalc { 'total_sorts' } )
. " sorts)" ;
push ( @ adjvars ,
"sort_buffer_size (> "
. hr_bytes_rnd ( $ myvar { 'sort_buffer_size' } )
. ")" ) ;
push ( @ adjvars ,
"read_rnd_buffer_size (> "
. hr_bytes_rnd ( $ myvar { 'read_rnd_buffer_size' } )
. ")" ) ;
}
else {
goodprint
"Sorts requiring temporary tables: $mycalc{'pct_temp_sort_table'}% ("
. hr_num ( $ mystat { 'Sort_merge_passes' } )
. " temp sorts / "
. hr_num ( $ mycalc { 'total_sorts' } )
. " sorts)" ;
}
# Joins
if ( $ mycalc { 'joins_without_indexes_per_day' } > 250 ) {
badprint
"Joins performed without indexes: $mycalc{'joins_without_indexes'}" ;
push ( @ adjvars ,
"join_buffer_size (> "
. hr_bytes ( $ myvar { 'join_buffer_size' } )
2018-05-27 14:03:29 +00:00
. ", or always use indexes with JOINs)" ) ;
2021-02-05 14:25:09 +00:00
push (
@ generalrec ,
" We will suggest raising the 'join_buffer_size' until JOINs not using indexes are found .
2023-09-09 10:22:32 +00:00
See https: // dev . mysql . com /doc/ refman /8.0/ en / server - system - variables . html #sysvar_join_buffer_size"
2021-02-05 14:25:09 +00:00
) ;
2015-08-19 12:45:24 +00:00
}
else {
2016-04-19 14:19:31 +00:00
goodprint "No joins without indexes" ;
2015-08-19 12:45:24 +00:00
# No joins have run without indexes
}
# Temporary tables
if ( $ mystat { 'Created_tmp_tables' } > 0 ) {
2016-11-03 09:36:59 +00:00
if ( $ mycalc { 'pct_temp_disk' } > 25
2015-08-19 12:45:24 +00:00
&& $ mycalc { 'max_tmp_table_size' } < 256 * 1024 * 1024 )
{
badprint
"Temporary tables created on disk: $mycalc{'pct_temp_disk'}% ("
. hr_num ( $ mystat { 'Created_tmp_disk_tables' } )
. " on disk / "
. hr_num ( $ mystat { 'Created_tmp_tables' } )
. " total)" ;
push ( @ adjvars ,
"tmp_table_size (> "
. hr_bytes_rnd ( $ myvar { 'tmp_table_size' } )
. ")" ) ;
push ( @ adjvars ,
"max_heap_table_size (> "
. hr_bytes_rnd ( $ myvar { 'max_heap_table_size' } )
. ")" ) ;
push ( @ generalrec ,
"When making adjustments, make tmp_table_size/max_heap_table_size equal"
) ;
push ( @ generalrec ,
2016-03-29 12:22:45 +00:00
"Reduce your SELECT DISTINCT queries which have no LIMIT clause"
) ;
2015-08-19 12:45:24 +00:00
}
elsif ( $ mycalc { 'pct_temp_disk' } > 25
&& $ mycalc { 'max_tmp_table_size' } >= 256 * 1024 * 1024 )
{
badprint
"Temporary tables created on disk: $mycalc{'pct_temp_disk'}% ("
. hr_num ( $ mystat { 'Created_tmp_disk_tables' } )
. " on disk / "
. hr_num ( $ mystat { 'Created_tmp_tables' } )
. " total)" ;
push ( @ generalrec ,
2022-09-13 13:17:39 +00:00
"Temporary table size is already large: reduce result set size"
2015-08-19 12:45:24 +00:00
) ;
push ( @ generalrec ,
"Reduce your SELECT DISTINCT queries without LIMIT clauses" ) ;
}
else {
goodprint
"Temporary tables created on disk: $mycalc{'pct_temp_disk'}% ("
. hr_num ( $ mystat { 'Created_tmp_disk_tables' } )
. " on disk / "
. hr_num ( $ mystat { 'Created_tmp_tables' } )
. " total)" ;
}
}
else {
2016-04-19 14:19:31 +00:00
goodprint "No tmp tables created on disk" ;
2015-08-19 12:45:24 +00:00
}
# Thread cache
2022-01-15 17:22:47 +00:00
if ( defined ( $ myvar { 'have_threadpool' } )
and $ myvar { 'have_threadpool' } eq 'YES' )
2018-09-26 07:31:19 +00:00
{
2022-02-04 15:01:22 +00:00
# https://www.percona.com/doc/percona-server/5.7/performance/threadpool.html#status-variables
# When thread pool is enabled, the value of the thread_cache_size variable
# is ignored. The Threads_cached status variable contains 0 in this case.
2022-01-15 17:22:47 +00:00
infoprint "Thread cache not used with thread pool enabled" ;
2018-09-26 09:10:09 +00:00
}
else {
2018-09-26 07:31:19 +00:00
if ( $ myvar { 'thread_cache_size' } eq 0 ) {
badprint "Thread cache is disabled" ;
2018-11-26 12:57:11 +00:00
push ( @ generalrec ,
"Set thread_cache_size to 4 as a starting value" ) ;
push ( @ adjvars , "thread_cache_size (start at 4)" ) ;
}
2016-08-31 08:30:20 +00:00
else {
if ( $ mycalc { 'thread_cache_hit_rate' } <= 50 ) {
badprint
"Thread cache hit rate: $mycalc{'thread_cache_hit_rate'}% ("
. hr_num ( $ mystat { 'Threads_created' } )
. " created / "
. hr_num ( $ mystat { 'Connections' } )
. " connections)" ;
push ( @ adjvars ,
"thread_cache_size (> $myvar{'thread_cache_size'})" ) ;
}
else {
goodprint
"Thread cache hit rate: $mycalc{'thread_cache_hit_rate'}% ("
. hr_num ( $ mystat { 'Threads_created' } )
. " created / "
. hr_num ( $ mystat { 'Connections' } )
. " connections)" ;
}
}
2016-08-30 11:45:46 +00:00
}
2015-08-19 12:45:24 +00:00
# Table cache
my $ table_cache_var = "" ;
if ( $ mystat { 'Open_tables' } > 0 ) {
if ( $ mycalc { 'table_cache_hit_rate' } < 20 ) {
2021-07-15 15:02:24 +00:00
2021-08-25 10:01:28 +00:00
unless ( defined ( $ mystat { 'Table_open_cache_hits' } ) ) {
badprint
"Table cache hit rate: $mycalc{'table_cache_hit_rate'}% ("
. hr_num ( $ mystat { 'Open_tables' } )
. " hits / "
. hr_num ( $ mystat { 'Opened_tables' } )
. " requests)" ;
}
else {
badprint
"Table cache hit rate: $mycalc{'table_cache_hit_rate'}% ("
. hr_num ( $ mystat { 'Table_open_cache_hits' } )
. " hits / "
. hr_num ( $ mystat { 'Table_open_cache_hits' } +
$ mystat { 'Table_open_cache_misses' } )
. " requests)" ;
}
2021-07-15 15:02:24 +00:00
2015-08-19 12:45:24 +00:00
if ( mysql_version_ge ( 5 , 1 ) ) {
$ table_cache_var = "table_open_cache" ;
}
else {
$ table_cache_var = "table_cache" ;
}
push ( @ adjvars ,
$ table_cache_var . " (> " . $ myvar { $ table_cache_var } . ")" ) ;
push ( @ generalrec ,
"Increase "
. $ table_cache_var
. " gradually to avoid file descriptor limits" ) ;
push ( @ generalrec ,
"Read this before increasing "
. $ table_cache_var
2020-01-09 06:53:56 +00:00
. " over 64: https://bit.ly/2Fulv7r" ) ;
2018-03-19 16:17:11 +00:00
push ( @ generalrec ,
2018-09-25 15:19:19 +00:00
"Read this before increasing for MariaDB"
2018-11-26 12:57:11 +00:00
. " https://mariadb.com/kb/en/library/optimizing-table_open_cache/"
) ;
2018-09-25 15:05:43 +00:00
push ( @ generalrec ,
2018-03-19 16:17:11 +00:00
"This is MyISAM only table_cache scalability problem, InnoDB not affected."
) ;
push ( @ generalrec ,
2022-06-30 12:46:54 +00:00
"For more details see: https://bugs.mysql.com/bug.php?id=49177"
2018-03-19 16:17:11 +00:00
) ;
push ( @ generalrec ,
"This bug already fixed in MySQL 5.7.9 and newer MySQL versions."
) ;
2015-08-19 12:45:24 +00:00
push ( @ generalrec ,
"Beware that open_files_limit ("
. $ myvar { 'open_files_limit' }
. ") variable " ) ;
push ( @ generalrec ,
2016-10-23 16:32:48 +00:00
"should be greater than $table_cache_var ("
2015-08-19 12:45:24 +00:00
. $ myvar { $ table_cache_var }
. ")" ) ;
}
else {
2021-08-25 10:01:28 +00:00
unless ( defined ( $ mystat { 'Table_open_cache_hits' } ) ) {
goodprint
"Table cache hit rate: $mycalc{'table_cache_hit_rate'}% ("
. hr_num ( $ mystat { 'Open_tables' } )
. " hits / "
. hr_num ( $ mystat { 'Opened_tables' } )
. " requests)" ;
}
else {
goodprint
"Table cache hit rate: $mycalc{'table_cache_hit_rate'}% ("
. hr_num ( $ mystat { 'Table_open_cache_hits' } )
. " hits / "
. hr_num ( $ mystat { 'Table_open_cache_hits' } +
$ mystat { 'Table_open_cache_misses' } )
. " requests)" ;
}
2015-08-19 12:45:24 +00:00
}
}
2019-10-03 19:29:03 +00:00
# Table definition cache
2021-02-05 14:25:09 +00:00
my $ nbtables = select_one ( 'SELECT COUNT(*) FROM information_schema.tables' ) ;
2021-01-28 08:12:56 +00:00
$ mycalc { 'total_tables' } = $ nbtables ;
2019-10-03 19:29:03 +00:00
if ( defined $ myvar { 'table_definition_cache' } ) {
if ( $ myvar { 'table_definition_cache' } == - 1 ) {
2022-06-30 12:46:54 +00:00
infoprint ( "table_definition_cache ("
2021-02-05 14:25:09 +00:00
. $ myvar { 'table_definition_cache' }
. ") is in autosizing mode" ) ;
}
elsif ( $ myvar { 'table_definition_cache' } < $ nbtables ) {
2022-06-15 12:43:18 +00:00
badprint "table_definition_cache ("
2021-02-05 14:25:09 +00:00
. $ myvar { 'table_definition_cache' }
2022-06-15 12:43:18 +00:00
. ") is less than number of tables ($nbtables) " ;
2019-10-03 19:29:03 +00:00
push ( @ adjvars ,
2022-06-30 12:46:54 +00:00
"table_definition_cache ("
2021-02-05 14:25:09 +00:00
. $ myvar { 'table_definition_cache' } . ") > "
. $ nbtables
. " or -1 (autosizing if supported)" ) ;
2019-10-03 19:29:03 +00:00
}
else {
2022-06-15 12:43:18 +00:00
goodprint "table_definition_cache ("
2021-02-05 14:25:09 +00:00
. $ myvar { 'table_definition_cache' }
2022-06-15 12:43:18 +00:00
. ") is greater than number of tables ($nbtables)" ;
2019-10-03 19:29:03 +00:00
}
2021-02-05 14:25:09 +00:00
}
else {
2019-10-03 19:29:03 +00:00
infoprint "No table_definition_cache variable found." ;
}
2015-08-19 12:45:24 +00:00
# Open files
if ( defined $ mycalc { 'pct_files_open' } ) {
if ( $ mycalc { 'pct_files_open' } > 85 ) {
badprint "Open file limit used: $mycalc{'pct_files_open'}% ("
. hr_num ( $ mystat { 'Open_files' } ) . "/"
. hr_num ( $ myvar { 'open_files_limit' } ) . ")" ;
push ( @ adjvars ,
"open_files_limit (> " . $ myvar { 'open_files_limit' } . ")" ) ;
2016-11-03 09:36:59 +00:00
}
else {
2015-08-19 12:45:24 +00:00
goodprint "Open file limit used: $mycalc{'pct_files_open'}% ("
. hr_num ( $ mystat { 'Open_files' } ) . "/"
. hr_num ( $ myvar { 'open_files_limit' } ) . ")" ;
}
}
# Table locks
if ( defined $ mycalc { 'pct_table_locks_immediate' } ) {
if ( $ mycalc { 'pct_table_locks_immediate' } < 95 ) {
badprint
"Table locks acquired immediately: $mycalc{'pct_table_locks_immediate'}%" ;
push ( @ generalrec ,
"Optimize queries and/or use InnoDB to reduce lock wait" ) ;
2016-11-03 09:36:59 +00:00
}
else {
2015-08-19 12:45:24 +00:00
goodprint
"Table locks acquired immediately: $mycalc{'pct_table_locks_immediate'}% ("
. hr_num ( $ mystat { 'Table_locks_immediate' } )
. " immediate / "
. hr_num ( $ mystat { 'Table_locks_waited' } +
$ mystat { 'Table_locks_immediate' } )
. " locks)" ;
}
}
# Binlog cache
if ( defined $ mycalc { 'pct_binlog_cache' } ) {
2016-11-03 09:36:59 +00:00
if ( $ mycalc { 'pct_binlog_cache' } < 90
&& $ mystat { 'Binlog_cache_use' } > 0 )
{
2015-08-19 12:45:24 +00:00
badprint "Binlog cache memory access: "
2016-10-23 16:32:48 +00:00
. $ mycalc { 'pct_binlog_cache' } . "% ("
2016-11-03 09:36:59 +00:00
. (
$ mystat { 'Binlog_cache_use' } - $ mystat { 'Binlog_cache_disk_use' } )
2015-08-19 12:45:24 +00:00
. " Memory / "
. $ mystat { 'Binlog_cache_use' }
. " Total)" ;
push ( @ generalrec ,
2023-02-27 16:49:36 +00:00
"Increase binlog_cache_size (current value: "
2015-08-19 12:45:24 +00:00
. $ myvar { 'binlog_cache_size' }
2016-10-23 16:32:48 +00:00
. ")" ) ;
2015-08-19 12:45:24 +00:00
push ( @ adjvars ,
"binlog_cache_size ("
. hr_bytes ( $ myvar { 'binlog_cache_size' } + 16 * 1024 * 1024 )
2016-10-23 16:32:48 +00:00
. ")" ) ;
2016-11-03 09:36:59 +00:00
}
else {
2015-08-19 12:45:24 +00:00
goodprint "Binlog cache memory access: "
2016-10-23 16:32:48 +00:00
. $ mycalc { 'pct_binlog_cache' } . "% ("
2016-11-03 09:36:59 +00:00
. (
$ mystat { 'Binlog_cache_use' } - $ mystat { 'Binlog_cache_disk_use' } )
2015-08-19 12:45:24 +00:00
. " Memory / "
. $ mystat { 'Binlog_cache_use' }
. " Total)" ;
2016-04-22 15:22:00 +00:00
debugprint "Not enough data to validate binlog cache size\n"
2015-08-19 12:45:24 +00:00
if $ mystat { 'Binlog_cache_use' } < 10 ;
}
}
# Performance options
if ( ! mysql_version_ge ( 5 , 1 ) ) {
2016-04-22 15:22:00 +00:00
push ( @ generalrec , "Upgrade to MySQL 5.5+ to use asynchronous write" ) ;
2016-11-03 09:36:59 +00:00
}
elsif ( $ myvar { 'concurrent_insert' } eq "OFF" ) {
2015-08-19 12:45:24 +00:00
push ( @ generalrec , "Enable concurrent_insert by setting it to 'ON'" ) ;
2016-11-03 09:36:59 +00:00
}
elsif ( $ myvar { 'concurrent_insert' } eq 0 ) {
2015-08-19 12:45:24 +00:00
push ( @ generalrec , "Enable concurrent_insert by setting it to 1" ) ;
}
}
2015-12-10 10:52:39 +00:00
# Recommendations for MyISAM
2015-08-19 12:45:24 +00:00
sub mysql_myisam {
2023-08-16 05:38:34 +00:00
return 0 unless ( $ opt { 'myisamstat' } > 0 ) ;
2016-04-11 10:01:01 +00:00
subheaderprint "MyISAM Metrics" ;
2023-06-22 14:55:58 +00:00
my $ nb_myisam_tables = select_one (
2023-07-06 06:19:29 +00:00
"SELECT COUNT(*) FROM information_schema.TABLES WHERE ENGINE='MyISAM' and TABLE_SCHEMA NOT IN ('mysql','information_schema','performance_schema')"
) ;
push ( @ generalrec ,
"MyISAM engine is deprecated, consider migrating to InnoDB" )
if $ nb_myisam_tables > 0 ;
if ( $ nb_myisam_tables > 0 ) {
badprint
2023-10-30 15:25:06 +00:00
"Consider migrating $nb_myisam_tables following tables to InnoDB:" ;
2023-07-06 06:19:29 +00:00
my $ sql_mig = "" ;
for my $ myisam_table (
select_array (
"SELECT CONCAT(TABLE_SCHEMA, '.', TABLE_NAME) FROM information_schema.TABLES WHERE ENGINE='MyISAM' and TABLE_SCHEMA NOT IN ('mysql','information_schema','performance_schema')"
)
)
{
$ sql_mig =
"${sql_mig}-- InnoDB migration for $myisam_table\nALTER TABLE $myisam_table ENGINE=InnoDB;\n\n" ;
infoprint
"* InnoDB migration request for $myisam_table Table: ALTER TABLE $myisam_table ENGINE=InnoDB;" ;
}
dump_into_file ( "migrate_myisam_to_innodb.sql" , $ sql_mig ) ;
}
2023-06-22 14:55:58 +00:00
infoprint ( "General MyIsam metrics:" ) ;
infoprint " +-- Total MyISAM Tables : $nb_myisam_tables" ;
infoprint " +-- Total MyISAM indexes : "
2023-07-06 06:19:29 +00:00
. hr_bytes ( $ mycalc { 'total_myisam_indexes' } )
if defined ( $ mycalc { 'total_myisam_indexes' } ) ;
infoprint " +-- KB Size :" . hr_bytes ( $ myvar { 'key_buffer_size' } ) ;
infoprint " +-- KB Used Size :"
. hr_bytes ( $ myvar { 'key_buffer_size' } -
$ mystat { 'Key_blocks_unused' } * $ myvar { 'key_cache_block_size' } ) ;
2023-06-22 14:55:58 +00:00
infoprint " +-- KB used :" . $ mycalc { 'pct_key_buffer_used' } . "%" ;
infoprint " +-- Read KB hit rate: $mycalc{'pct_keys_from_mem'}% ("
2023-07-06 06:19:29 +00:00
. hr_num ( $ mystat { 'Key_read_requests' } )
. " cached / "
. hr_num ( $ mystat { 'Key_reads' } )
. " reads)" ;
2023-06-22 14:55:58 +00:00
infoprint " +-- Write KB hit rate: $mycalc{'pct_wkeys_from_mem'}% ("
2023-07-06 06:19:29 +00:00
. hr_num ( $ mystat { 'Key_write_requests' } )
. " cached / "
. hr_num ( $ mystat { 'Key_writes' } )
. " writes)" ;
2023-06-22 14:55:58 +00:00
if ( $ nb_myisam_tables == 0 ) {
infoprint "No MyISAM table(s) detected ...." ;
return ;
}
2021-02-05 14:25:09 +00:00
if ( mysql_version_ge ( 8 ) and mysql_version_le ( 10 ) ) {
2022-06-30 12:46:54 +00:00
infoprint "MyISAM Metrics are disabled since MySQL 8.0." ;
2022-06-23 12:31:46 +00:00
if ( $ myvar { 'key_buffer_size' } > 0 ) {
2022-03-12 17:46:42 +00:00
push ( @ adjvars , "key_buffer_size=0" ) ;
2022-06-23 12:31:46 +00:00
push ( @ generalrec ,
"Buffer Key MyISAM set to 0, no MyISAM table detected" ) ;
2022-03-12 17:46:42 +00:00
}
2019-09-25 21:29:22 +00:00
return ;
}
2023-07-06 06:19:29 +00:00
2023-06-22 14:55:58 +00:00
if ( ! defined ( $ mycalc { 'total_myisam_indexes' } ) ) {
2023-07-06 06:19:29 +00:00
badprint
"Unable to calculate MyISAM index size on MySQL server < 5.0.0" ;
2023-06-22 14:55:58 +00:00
push ( @ generalrec ,
"Unable to calculate MyISAM index size on MySQL server < 5.0.0" ) ;
2022-03-11 08:42:01 +00:00
return ;
}
2023-06-22 14:55:58 +00:00
if ( $ mycalc { 'pct_key_buffer_used' } == 0 ) {
2023-07-06 06:19:29 +00:00
2015-08-19 12:45:24 +00:00
# No queries have run that would use keys
2023-06-22 14:55:58 +00:00
infoprint "Key buffer used: $mycalc{'pct_key_buffer_used'}% ("
2021-11-22 13:49:23 +00:00
. hr_bytes ( $ myvar { 'key_buffer_size' } -
2022-02-04 15:01:22 +00:00
$ mystat { 'Key_blocks_unused' } * $ myvar { 'key_cache_block_size' } )
2015-08-19 12:45:24 +00:00
. " used / "
2021-11-22 13:49:23 +00:00
. hr_bytes ( $ myvar { 'key_buffer_size' } )
2015-08-19 12:45:24 +00:00
. " cache)" ;
2023-06-22 14:55:58 +00:00
infoprint "No SQL statement based on MyISAM table(s) detected ...." ;
2023-07-06 06:19:29 +00:00
return ;
2015-11-23 07:08:25 +00:00
}
2015-08-19 12:45:24 +00:00
2023-06-22 14:55:58 +00:00
# Key buffer usage
if ( $ mycalc { 'pct_key_buffer_used' } < 90 ) {
badprint "Key buffer used: $mycalc{'pct_key_buffer_used'}% ("
. hr_bytes ( $ myvar { 'key_buffer_size' } -
2023-07-06 06:19:29 +00:00
$ mystat { 'Key_blocks_unused' } * $ myvar { 'key_cache_block_size' } )
2023-06-22 14:55:58 +00:00
. " used / "
. hr_bytes ( $ myvar { 'key_buffer_size' } )
. " cache)" ;
push (
@ adjvars ,
"key_buffer_size (\~ "
. hr_num (
2023-07-06 06:19:29 +00:00
$ myvar { 'key_buffer_size' } *
$ mycalc { 'pct_key_buffer_used' } / 100
2023-06-22 14:55:58 +00:00
)
. ")"
) ;
2023-07-06 06:19:29 +00:00
}
else {
goodprint "Key buffer used: $mycalc{'pct_key_buffer_used'}% ("
2023-06-22 14:55:58 +00:00
. hr_bytes ( $ myvar { 'key_buffer_size' } -
2023-07-06 06:19:29 +00:00
$ mystat { 'Key_blocks_unused' } * $ myvar { 'key_cache_block_size' } )
. " used / "
. hr_bytes ( $ myvar { 'key_buffer_size' } )
. " cache)" ;
2023-06-22 14:55:58 +00:00
}
# Key buffer size / total MyISAM indexes
if ( $ myvar { 'key_buffer_size' } < $ mycalc { 'total_myisam_indexes' }
&& $ mycalc { 'pct_keys_from_mem' } < 95 )
{
badprint "Key buffer size / total MyISAM indexes: "
. hr_bytes ( $ myvar { 'key_buffer_size' } ) . "/"
. hr_bytes ( $ mycalc { 'total_myisam_indexes' } ) . "" ;
push ( @ adjvars ,
"key_buffer_size (> "
. hr_bytes ( $ mycalc { 'total_myisam_indexes' } )
. ")" ) ;
2016-11-03 09:36:59 +00:00
}
else {
2023-06-22 14:55:58 +00:00
goodprint "Key buffer size / total MyISAM indexes: "
. hr_bytes ( $ myvar { 'key_buffer_size' } ) . "/"
. hr_bytes ( $ mycalc { 'total_myisam_indexes' } ) . "" ;
}
if ( $ mystat { 'Key_read_requests' } > 0 ) {
if ( $ mycalc { 'pct_keys_from_mem' } < 95 ) {
badprint
"Read Key buffer hit rate: $mycalc{'pct_keys_from_mem'}% ("
. hr_num ( $ mystat { 'Key_read_requests' } )
. " cached / "
. hr_num ( $ mystat { 'Key_reads' } )
. " reads)" ;
2016-11-03 09:36:59 +00:00
}
else {
2023-06-22 14:55:58 +00:00
goodprint
"Read Key buffer hit rate: $mycalc{'pct_keys_from_mem'}% ("
. hr_num ( $ mystat { 'Key_read_requests' } )
. " cached / "
. hr_num ( $ mystat { 'Key_reads' } )
. " reads)" ;
2016-11-03 09:36:59 +00:00
}
2023-06-22 14:55:58 +00:00
}
2017-07-05 09:51:33 +00:00
2023-06-22 14:55:58 +00:00
# No queries have run that would use keys
debugprint "Key buffer size / total MyISAM indexes: "
. hr_bytes ( $ myvar { 'key_buffer_size' } ) . "/"
. hr_bytes ( $ mycalc { 'total_myisam_indexes' } ) . "" ;
if ( $ mystat { 'Key_write_requests' } > 0 ) {
if ( $ mycalc { 'pct_wkeys_from_mem' } < 95 ) {
badprint
"Write Key buffer hit rate: $mycalc{'pct_wkeys_from_mem'}% ("
. hr_num ( $ mystat { 'Key_write_requests' } )
. " cached / "
. hr_num ( $ mystat { 'Key_writes' } )
. " writes)" ;
2016-11-03 09:36:59 +00:00
}
else {
2023-06-22 14:55:58 +00:00
goodprint
2015-08-19 12:45:24 +00:00
"Write Key buffer hit rate: $mycalc{'pct_wkeys_from_mem'}% ("
. hr_num ( $ mystat { 'Key_write_requests' } )
. " cached / "
. hr_num ( $ mystat { 'Key_writes' } )
. " writes)" ;
}
2023-07-06 06:19:29 +00:00
}
else {
# No queries have run that would use keys
debugprint
"Write Key buffer hit rate: $mycalc{'pct_wkeys_from_mem'}% ("
. hr_num ( $ mystat { 'Key_write_requests' } )
. " cached / "
. hr_num ( $ mystat { 'Key_writes' } )
. " writes)" ;
2015-08-19 12:45:24 +00:00
}
}
2011-03-08 18:38:37 +00:00
2016-01-27 18:00:27 +00:00
# Recommendations for ThreadPool
sub mariadb_threadpool {
2016-04-11 10:01:01 +00:00
subheaderprint "ThreadPool Metrics" ;
2016-01-27 18:00:27 +00:00
2022-06-15 12:43:18 +00:00
# MariaDB
2016-01-27 18:00:27 +00:00
unless ( defined $ myvar { 'have_threadpool' }
2016-03-22 14:20:18 +00:00
&& $ myvar { 'have_threadpool' } eq "YES" )
2016-01-27 18:00:27 +00:00
{
infoprint "ThreadPool stat is disabled." ;
return ;
}
2016-03-29 12:22:45 +00:00
infoprint "ThreadPool stat is enabled." ;
infoprint "Thread Pool Size: " . $ myvar { 'thread_pool_size' } . " thread(s)." ;
2016-03-22 14:20:18 +00:00
2022-02-04 15:01:22 +00:00
if ( $ myvar { 'version' } =~ /percona/i
or $ myvar { 'version_comment' } =~ /percona/i )
{
2021-07-02 16:31:21 +00:00
my $ np = cpu_cores ;
if ( $ myvar { 'thread_pool_size' } >= $ np
and $ myvar { 'thread_pool_size' } < ( $ np * 1.5 ) )
{
goodprint
2021-10-16 15:07:14 +00:00
"thread_pool_size for Percona between 1 and 1.5 times number of CPUs ("
2021-07-02 16:31:21 +00:00
. $ np . " and "
. ( $ np * 1.5 ) . ")" ;
}
else {
badprint
2021-10-16 15:07:14 +00:00
"thread_pool_size for Percona between 1 and 1.5 times number of CPUs ("
2021-07-02 16:31:21 +00:00
. $ np . " and "
. ( $ np * 1.5 ) . ")" ;
push ( @ adjvars ,
"thread_pool_size between "
. $ np . " and "
. ( $ np * 1.5 )
. " for InnoDB usage" ) ;
}
2021-05-03 12:00:02 +00:00
return ;
}
2021-07-02 16:31:21 +00:00
2021-05-03 12:00:02 +00:00
if ( $ myvar { 'version' } =~ /mariadb/i ) {
2016-04-22 15:22:00 +00:00
infoprint "Using default value is good enough for your version ("
2016-04-19 14:19:31 +00:00
. $ myvar { 'version' } . ")" ;
return ;
}
2016-03-22 14:20:18 +00:00
2016-03-29 12:22:45 +00:00
if ( $ myvar { 'have_innodb' } eq 'YES' ) {
2016-11-03 09:36:59 +00:00
if ( $ myvar { 'thread_pool_size' } < 16
2016-03-29 12:22:45 +00:00
or $ myvar { 'thread_pool_size' } > 36 )
{
badprint
"thread_pool_size between 16 and 36 when using InnoDB storage engine." ;
push ( @ generalrec ,
"Thread pool size for InnoDB usage ("
. $ myvar { 'thread_pool_size' }
. ")" ) ;
push ( @ adjvars ,
"thread_pool_size between 16 and 36 for InnoDB usage" ) ;
}
else {
goodprint
"thread_pool_size between 16 and 36 when using InnoDB storage engine." ;
2016-03-22 14:20:18 +00:00
}
return ;
2016-03-29 12:22:45 +00:00
}
if ( $ myvar { 'have_isam' } eq 'YES' ) {
if ( $ myvar { 'thread_pool_size' } < 4 or $ myvar { 'thread_pool_size' } > 8 )
{
badprint
2022-06-30 12:46:54 +00:00
"thread_pool_size between 4 and 8 when using MyISAM storage engine." ;
2016-03-29 12:22:45 +00:00
push ( @ generalrec ,
2022-06-30 12:46:54 +00:00
"Thread pool size for MyISAM usage ("
2016-03-29 12:22:45 +00:00
. $ myvar { 'thread_pool_size' }
. ")" ) ;
push ( @ adjvars ,
2022-06-30 12:46:54 +00:00
"thread_pool_size between 4 and 8 for MyISAM usage" ) ;
2016-03-29 12:22:45 +00:00
}
else {
goodprint
"thread_pool_size between 4 and 8 when using MyISAM storage engine." ;
2016-03-22 14:20:18 +00:00
}
}
2016-01-27 18:00:27 +00:00
}
2016-04-19 14:19:31 +00:00
sub get_pf_memory {
2016-04-11 10:01:01 +00:00
# Performance Schema
2016-04-18 09:07:05 +00:00
return 0 unless defined $ myvar { 'performance_schema' } ;
return 0 if $ myvar { 'performance_schema' } eq 'OFF' ;
2016-04-19 14:19:31 +00:00
2022-10-31 23:30:08 +00:00
my @ infoPFSMemory = grep { /\tperformance_schema[.]memory\t/msx }
2016-04-19 14:19:31 +00:00
select_array ( "SHOW ENGINE PERFORMANCE_SCHEMA STATUS" ) ;
2022-10-31 23:30:08 +00:00
@ infoPFSMemory == 1 || return 0 ;
2016-04-05 15:40:38 +00:00
$ infoPFSMemory [ 0 ] =~ s/.*\s+(\d+)$/$1/g ;
return $ infoPFSMemory [ 0 ] ;
}
2016-04-19 14:19:31 +00:00
2016-03-16 17:40:44 +00:00
# Recommendations for Performance Schema
2023-06-07 15:23:33 +00:00
sub mysql_pfs {
2016-04-11 10:01:01 +00:00
subheaderprint "Performance schema" ;
2016-03-16 17:40:44 +00:00
# Performance Schema
2023-06-17 20:36:31 +00:00
debugprint "Performance schema is " . $ myvar { 'performance_schema' } ;
2022-02-07 22:34:34 +00:00
$ myvar { 'performance_schema' } = 'OFF'
unless defined ( $ myvar { 'performance_schema' } ) ;
2022-06-23 12:31:46 +00:00
if ( $ myvar { 'performance_schema' } eq 'OFF' ) {
2022-02-07 21:48:37 +00:00
badprint "Performance_schema should be activated." ;
push ( @ adjvars , "performance_schema=ON" ) ;
2022-02-07 22:34:34 +00:00
push ( @ generalrec ,
2022-06-23 12:31:46 +00:00
"Performance schema should be activated for better diagnostics" ) ;
}
2022-02-07 21:48:37 +00:00
if ( $ myvar { 'performance_schema' } eq 'ON' ) {
infoprint "Performance_schema is activated." ;
debugprint "Performance schema is " . $ myvar { 'performance_schema' } ;
2022-12-29 04:13:02 +00:00
infoprint "Memory used by Performance_schema: "
. hr_bytes ( get_pf_memory ( ) ) ;
2018-02-22 15:11:42 +00:00
}
2022-01-30 14:38:54 +00:00
2016-09-19 14:13:22 +00:00
unless ( grep /^sys$/ , select_array ( "SHOW DATABASES" ) ) {
2022-06-30 12:46:54 +00:00
infoprint "Sys schema is not installed." ;
2018-01-10 14:14:19 +00:00
push ( @ generalrec ,
2023-03-11 06:48:00 +00:00
mysql_version_ge ( 10 , 0 )
? "Consider installing Sys schema from https://github.com/FromDual/mariadb-sys for MariaDB"
: "Consider installing Sys schema from https://github.com/mysql/mysql-sys for MySQL"
2018-11-26 13:31:59 +00:00
) unless ( mysql_version_le ( 5 , 6 ) ) ;
2019-03-06 13:10:17 +00:00
2016-11-03 09:36:59 +00:00
return ;
2016-04-21 21:16:35 +00:00
}
2022-03-10 21:01:36 +00:00
infoprint "Sys schema is installed." ;
2017-02-07 05:56:17 +00:00
return if ( $ opt { pfstat } == 0 or $ myvar { 'performance_schema' } ne 'ON' ) ;
2016-10-24 09:21:56 +00:00
2016-11-03 09:36:59 +00:00
infoprint "Sys schema Version: "
. select_one ( "select sys_version from sys.version" ) ;
2016-09-27 14:07:26 +00:00
2023-03-11 06:48:00 +00:00
# Store all sys schema in dumpdir if defined
if ( defined $ opt { dumpdir } and - d "$opt{dumpdir}" ) {
2023-06-05 20:40:49 +00:00
for my $ sys_view ( select_array ( 'use sys;show tables;' ) ) {
infoprint "Dumping $sys_view into $opt{dumpdir}" ;
2023-07-06 06:19:29 +00:00
my $ sys_view_table = $ sys_view ;
2023-06-17 20:36:31 +00:00
$ sys_view_table =~ s/\$/\\\$/g ;
2023-07-06 06:19:29 +00:00
select_csv_file ( "$opt{dumpdir}/sys_$sys_view.csv" ,
'select * from sys.\`' . $ sys_view_table . '\`' ) ;
2023-03-11 06:48:00 +00:00
}
2023-06-17 20:36:31 +00:00
return ;
2023-07-06 06:19:29 +00:00
2023-06-07 17:29:41 +00:00
#exit 0 if ( $opt{stop} == 1 );
2023-03-01 10:16:44 +00:00
}
2023-03-11 06:48:00 +00:00
# Top user per connection
2016-09-27 14:07:26 +00:00
subheaderprint "Performance schema: Top 5 user per connection" ;
2016-11-03 09:36:59 +00:00
my $ nbL = 1 ;
for my $ lQuery (
select_array (
'select user, total_connections from sys.user_summary order by total_connections desc LIMIT 5'
)
)
{
infoprint " +-- $nbL: $lQuery conn(s)" ;
$ nbL + + ;
2016-09-27 14:07:26 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-27 14:07:26 +00:00
2016-10-24 09:21:56 +00:00
# Top user per statement
2016-09-27 14:07:26 +00:00
subheaderprint "Performance schema: Top 5 user per statement" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
'select user, statements from sys.user_summary order by statements desc LIMIT 5'
)
)
{
infoprint " +-- $nbL: $lQuery stmt(s)" ;
$ nbL + + ;
2016-09-27 14:07:26 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-27 14:07:26 +00:00
2016-10-10 13:34:29 +00:00
# Top user per statement latency
2016-09-27 14:07:26 +00:00
subheaderprint "Performance schema: Top 5 user per statement latency" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select user, statement_avg_latency from sys.x\\$user_summary order by statement_avg_latency desc LIMIT 5'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-27 14:07:26 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-27 14:07:26 +00:00
2016-10-10 13:34:29 +00:00
# Top user per lock latency
2016-09-27 14:07:26 +00:00
subheaderprint "Performance schema: Top 5 user per lock latency" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select user, lock_latency from sys.x\\$user_summary_by_statement_latency order by lock_latency desc LIMIT 5'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-27 14:07:26 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-27 14:07:26 +00:00
2016-10-10 13:34:29 +00:00
# Top user per full scans
2016-09-27 14:07:26 +00:00
subheaderprint "Performance schema: Top 5 user per nb full scans" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select user, full_scans from sys.x\\$user_summary_by_statement_latency order by full_scans desc LIMIT 5'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-27 14:07:26 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-24 09:21:56 +00:00
2016-10-10 13:34:29 +00:00
# Top user per row_sent
2016-09-27 14:07:26 +00:00
subheaderprint "Performance schema: Top 5 user per rows sent" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select user, rows_sent from sys.x\\$user_summary_by_statement_latency order by rows_sent desc LIMIT 5'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-27 14:07:26 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-24 09:21:56 +00:00
2016-10-10 13:34:29 +00:00
# Top user per row modified
2016-09-27 14:07:26 +00:00
subheaderprint "Performance schema: Top 5 user per rows modified" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select user, rows_affected from sys.x\\$user_summary_by_statement_latency order by rows_affected desc LIMIT 5'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-27 14:07:26 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-27 14:07:26 +00:00
2016-10-10 13:34:29 +00:00
# Top user per io
2022-06-15 12:43:18 +00:00
subheaderprint "Performance schema: Top 5 user per IO" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select user, file_ios from sys.x\\$user_summary order by file_ios desc LIMIT 5'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-27 14:07:26 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-27 14:07:26 +00:00
2016-10-10 13:34:29 +00:00
# Top user per io latency
2022-06-15 12:43:18 +00:00
subheaderprint "Performance schema: Top 5 user per IO latency" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select user, file_io_latency from sys.x\\$user_summary order by file_io_latency desc LIMIT 5'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-27 14:07:26 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-27 14:07:26 +00:00
2016-10-24 09:21:56 +00:00
# Top host per connection
2016-09-26 16:32:35 +00:00
subheaderprint "Performance schema: Top 5 host per connection" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select host, total_connections from sys.x\\$host_summary order by total_connections desc LIMIT 5'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery conn(s)" ;
$ nbL + + ;
2016-09-26 16:32:35 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-26 16:32:35 +00:00
2016-10-24 09:21:56 +00:00
# Top host per statement
2016-09-26 16:32:35 +00:00
subheaderprint "Performance schema: Top 5 host per statement" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select host, statements from sys.x\\$host_summary order by statements desc LIMIT 5'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery stmt(s)" ;
$ nbL + + ;
2016-09-26 16:32:35 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-26 16:32:35 +00:00
# Top host per statement latency
subheaderprint "Performance schema: Top 5 host per statement latency" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select host, statement_avg_latency from sys.x\\$host_summary order by statement_avg_latency desc LIMIT 5'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-26 16:32:35 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-26 16:32:35 +00:00
# Top host per lock latency
subheaderprint "Performance schema: Top 5 host per lock latency" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select host, lock_latency from sys.x\\$host_summary_by_statement_latency order by lock_latency desc LIMIT 5'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-26 16:32:35 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-26 16:32:35 +00:00
# Top host per full scans
subheaderprint "Performance schema: Top 5 host per nb full scans" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select host, full_scans from sys.x\\$host_summary_by_statement_latency order by full_scans desc LIMIT 5'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-26 16:32:35 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-24 09:21:56 +00:00
2016-10-10 13:34:29 +00:00
# Top host per rows sent
2016-09-26 16:32:35 +00:00
subheaderprint "Performance schema: Top 5 host per rows sent" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select host, rows_sent from sys.x\\$host_summary_by_statement_latency order by rows_sent desc LIMIT 5'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-26 16:32:35 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-24 09:21:56 +00:00
2016-10-10 13:34:29 +00:00
# Top host per rows modified
2016-09-26 16:32:35 +00:00
subheaderprint "Performance schema: Top 5 host per rows modified" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select host, rows_affected from sys.x\\$host_summary_by_statement_latency order by rows_affected desc LIMIT 5'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-19 14:13:22 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-19 14:13:22 +00:00
2016-09-26 16:32:35 +00:00
# Top host per io
subheaderprint "Performance schema: Top 5 host per io" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select host, file_ios from sys.x\\$host_summary order by file_ios desc LIMIT 5'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-26 16:32:35 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-26 16:32:35 +00:00
2016-10-10 13:34:29 +00:00
# Top 5 host per io latency
2016-09-26 16:32:35 +00:00
subheaderprint "Performance schema: Top 5 host per io latency" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select host, file_io_latency from sys.x\\$host_summary order by file_io_latency desc LIMIT 5'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-26 16:32:35 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-26 16:32:35 +00:00
2016-10-10 13:34:29 +00:00
# Top IO type order by total io
2016-09-26 16:32:35 +00:00
subheaderprint "Performance schema: Top IO type order by total io" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select substring(event_name,14), SUM(total)AS total from sys.x\\$host_summary_by_file_io_type GROUP BY substring(event_name,14) ORDER BY total DESC;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery i/o" ;
$ nbL + + ;
2016-09-26 16:32:35 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-26 16:32:35 +00:00
2016-10-10 13:34:29 +00:00
# Top IO type order by total latency
2016-09-26 16:32:35 +00:00
subheaderprint "Performance schema: Top IO type order by total latency" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select substring(event_name,14), ROUND(SUM(total_latency),1) AS total_latency from sys.x\\$host_summary_by_file_io_type GROUP BY substring(event_name,14) ORDER BY total_latency DESC;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-26 16:32:35 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-26 16:32:35 +00:00
2016-10-10 13:34:29 +00:00
# Top IO type order by max latency
2016-09-26 16:32:35 +00:00
subheaderprint "Performance schema: Top IO type order by max latency" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select substring(event_name,14), MAX(max_latency) as max_latency from sys.x\\$host_summary_by_file_io_type GROUP BY substring(event_name,14) ORDER BY max_latency DESC;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-26 16:32:35 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-24 09:21:56 +00:00
2016-10-10 13:34:29 +00:00
# Top Stages order by total io
2016-09-26 16:32:35 +00:00
subheaderprint "Performance schema: Top Stages order by total io" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select substring(event_name,7), SUM(total)AS total from sys.x\\$host_summary_by_stages GROUP BY substring(event_name,7) ORDER BY total DESC;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery i/o" ;
$ nbL + + ;
2016-09-26 16:32:35 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-26 16:32:35 +00:00
2016-10-10 13:34:29 +00:00
# Top Stages order by total latency
2016-09-26 16:32:35 +00:00
subheaderprint "Performance schema: Top Stages order by total latency" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select substring(event_name,7), ROUND(SUM(total_latency),1) AS total_latency from sys.x\\$host_summary_by_stages GROUP BY substring(event_name,7) ORDER BY total_latency DESC;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-26 16:32:35 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-26 16:32:35 +00:00
2016-10-10 13:34:29 +00:00
# Top Stages order by avg latency
2016-09-26 16:32:35 +00:00
subheaderprint "Performance schema: Top Stages order by avg latency" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select substring(event_name,7), MAX(avg_latency) as avg_latency from sys.x\\$host_summary_by_stages GROUP BY substring(event_name,7) ORDER BY avg_latency DESC;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-26 16:32:35 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-26 16:32:35 +00:00
# Top host per table scans
subheaderprint "Performance schema: Top 5 host per table scans" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select host, table_scans from sys.x\\$host_summary order by table_scans desc LIMIT 5'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-26 16:32:35 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2018-03-19 16:17:11 +00:00
2016-10-06 08:44:58 +00:00
# InnoDB Buffer Pool by schema
subheaderprint "Performance schema: InnoDB Buffer Pool by schema" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select object_schema, allocated, data, pages from sys.x\\$innodb_buffer_stats_by_schema ORDER BY pages DESC'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery page(s)" ;
$ nbL + + ;
2016-10-06 08:44:58 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-06 08:44:58 +00:00
# InnoDB Buffer Pool by table
2019-10-01 22:07:46 +00:00
subheaderprint "Performance schema: 40 InnoDB Buffer Pool by table" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'select object_schema, object_name, allocated,data, pages from sys.x\\$innodb_buffer_stats_by_table ORDER BY pages DESC LIMIT 40'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery page(s)" ;
$ nbL + + ;
2016-10-06 08:44:58 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-06 08:44:58 +00:00
2016-10-10 13:34:29 +00:00
# Process per allocated memory
2018-02-22 17:42:32 +00:00
subheaderprint "Performance schema: Process per time" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select user, Command AS PROC, time from sys.x\\$processlist ORDER BY time DESC;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-06 08:44:58 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-06 08:44:58 +00:00
2016-10-10 13:34:29 +00:00
# InnoDB Lock Waits
subheaderprint "Performance schema: InnoDB Lock Waits" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select wait_age_secs, locked_table, locked_type, waiting_query from sys.x\\$innodb_lock_waits order by wait_age_secs DESC;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 13:34:29 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-24 09:21:56 +00:00
2016-10-10 13:34:29 +00:00
# Threads IO Latency
subheaderprint "Performance schema: Thread IO Latency" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select user, total_latency, max_latency from sys.x\\$io_by_thread_by_latency order by total_latency DESC;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 13:34:29 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 13:34:29 +00:00
2016-10-24 09:21:56 +00:00
# High Cost SQL statements
2019-10-01 22:07:46 +00:00
subheaderprint "Performance schema: Top 15 Most latency statements" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'select LEFT(query, 120), avg_latency from sys.x\\$statement_analysis order by avg_latency desc LIMIT 15'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-26 16:32:35 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-24 09:21:56 +00:00
# Top 5% slower queries
2019-10-01 22:07:46 +00:00
subheaderprint "Performance schema: Top 15 slower queries" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'select LEFT(query, 120), exec_count from sys.x\\$statements_with_runtimes_in_95th_percentile order by exec_count desc LIMIT 15'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery s" ;
$ nbL + + ;
2016-09-19 14:13:22 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-26 16:32:35 +00:00
2016-10-10 13:34:29 +00:00
# Top 10 nb statement type
2019-10-01 22:07:46 +00:00
subheaderprint "Performance schema: Top 15 nb statement type" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'use sys;select statement, sum(total) as total from sys.x\\$host_summary_by_statement_type group by statement order by total desc LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-26 16:32:35 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-26 16:32:35 +00:00
2016-10-10 13:34:29 +00:00
# Top statement by total latency
2019-10-01 22:07:46 +00:00
subheaderprint "Performance schema: Top 15 statement by total latency" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'use sys;select statement, sum(total_latency) as total from sys.x\\$host_summary_by_statement_type group by statement order by total desc LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-26 16:32:35 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-26 16:32:35 +00:00
2016-10-10 13:34:29 +00:00
# Top statement by lock latency
2019-10-01 22:07:46 +00:00
subheaderprint "Performance schema: Top 15 statement by lock latency" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'use sys;select statement, sum(lock_latency) as total from sys.x\\$host_summary_by_statement_type group by statement order by total desc LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-26 16:32:35 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-26 16:32:35 +00:00
2016-10-10 13:34:29 +00:00
# Top statement by full scans
2019-10-01 22:07:46 +00:00
subheaderprint "Performance schema: Top 15 statement by full scans" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'use sys;select statement, sum(full_scans) as total from sys.x\\$host_summary_by_statement_type group by statement order by total desc LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-26 16:32:35 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-26 16:32:35 +00:00
2016-10-10 13:34:29 +00:00
# Top statement by rows sent
2019-10-01 22:07:46 +00:00
subheaderprint "Performance schema: Top 15 statement by rows sent" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'use sys;select statement, sum(rows_sent) as total from sys.x\\$host_summary_by_statement_type group by statement order by total desc LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-26 16:32:35 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-26 16:32:35 +00:00
2016-10-10 13:34:29 +00:00
# Top statement by rows modified
2019-10-01 22:07:46 +00:00
subheaderprint "Performance schema: Top 15 statement by rows modified" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'use sys;select statement, sum(rows_affected) as total from sys.x\\$host_summary_by_statement_type group by statement order by total desc LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-26 16:32:35 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-26 16:32:35 +00:00
2016-10-24 09:21:56 +00:00
# Use temporary tables
2019-10-01 22:07:46 +00:00
subheaderprint "Performance schema: 15 sample queries using temp table" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'use sys;select left(query, 120) from sys.x\\$statements_with_temp_tables LIMIT 15'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-19 14:13:22 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-24 09:21:56 +00:00
# Unused Indexes
2016-09-26 16:32:35 +00:00
subheaderprint "Performance schema: Unused indexes" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
2021-02-05 14:25:09 +00:00
for my $ lQuery (
select_array (
"select \* from sys.schema_unused_indexes where object_schema not in ('performance_schema')"
)
)
{
2016-11-03 09:36:59 +00:00
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-19 14:13:22 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-09-26 16:32:35 +00:00
2016-10-24 09:21:56 +00:00
# Full table scans
2016-09-26 16:32:35 +00:00
subheaderprint "Performance schema: Tables with full table scans" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select * from sys.x\\$schema_tables_with_full_table_scans order by rows_full_scanned DESC'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-09-19 14:13:22 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 13:34:29 +00:00
# Latest file IO by latency
2022-06-15 12:43:18 +00:00
subheaderprint "Performance schema: Latest File IO by latency" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select thread, file, latency, operation from sys.x\\$latest_file_io ORDER BY latency LIMIT 10;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 13:34:29 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 13:34:29 +00:00
2016-10-24 09:25:07 +00:00
# FILE by IO read bytes
2022-06-15 12:43:18 +00:00
subheaderprint "Performance schema: File by IO read bytes" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select file, total_read from sys.x\\$io_global_by_file_by_bytes order by total_read DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 13:34:29 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 13:34:29 +00:00
2016-10-24 09:25:07 +00:00
# FILE by IO written bytes
2022-06-15 12:43:18 +00:00
subheaderprint "Performance schema: File by IO written bytes" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select file, total_written from sys.x\\$io_global_by_file_by_bytes order by total_written DESC LIMIT 15'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 13:34:29 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 13:34:29 +00:00
# file per IO total latency
2022-06-15 12:43:18 +00:00
subheaderprint "Performance schema: File per IO total latency" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select file, total_latency from sys.x\\$io_global_by_file_by_latency ORDER BY total_latency DESC LIMIT 20;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 13:34:29 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 13:34:29 +00:00
# file per IO read latency
subheaderprint "Performance schema: file per IO read latency" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select file, read_latency from sys.x\\$io_global_by_file_by_latency ORDER BY read_latency DESC LIMIT 20;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 13:34:29 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 13:34:29 +00:00
# file per IO write latency
subheaderprint "Performance schema: file per IO write latency" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select file, write_latency from sys.x\\$io_global_by_file_by_latency ORDER BY write_latency DESC LIMIT 20;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 13:34:29 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 13:34:29 +00:00
2016-10-10 14:00:15 +00:00
# Event Wait by read bytes
subheaderprint "Performance schema: Event Wait by read bytes" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select event_name, total_read from sys.x\\$io_global_by_wait_by_bytes order by total_read DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 14:00:15 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 14:00:15 +00:00
# Event Wait by write bytes
2016-10-24 09:25:07 +00:00
subheaderprint "Performance schema: Event Wait written bytes" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select event_name, total_written from sys.x\\$io_global_by_wait_by_bytes order by total_written DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 13:34:29 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 13:34:29 +00:00
2016-10-10 16:14:52 +00:00
# event per wait total latency
2016-10-10 14:54:45 +00:00
subheaderprint "Performance schema: event per wait total latency" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select event_name, total_latency from sys.x\\$io_global_by_wait_by_latency ORDER BY total_latency DESC LIMIT 20;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 14:54:45 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 14:54:45 +00:00
# event per wait read latency
subheaderprint "Performance schema: event per wait read latency" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select event_name, read_latency from sys.x\\$io_global_by_wait_by_latency ORDER BY read_latency DESC LIMIT 20;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 14:54:45 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 14:54:45 +00:00
# event per wait write latency
subheaderprint "Performance schema: event per wait write latency" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select event_name, write_latency from sys.x\\$io_global_by_wait_by_latency ORDER BY write_latency DESC LIMIT 20;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 14:54:45 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 14:54:45 +00:00
2016-10-10 16:14:52 +00:00
#schema_index_statistics
# TOP 15 most read index
2022-06-30 12:46:54 +00:00
subheaderprint "Performance schema: Top 15 most read indexes" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select table_schema, table_name,index_name, rows_selected from sys.x\\$schema_index_statistics ORDER BY ROWs_selected DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 16:14:52 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 16:14:52 +00:00
# TOP 15 most used index
2022-06-15 12:43:18 +00:00
subheaderprint "Performance schema: Top 15 most modified indexes" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select table_schema, table_name,index_name, rows_inserted+rows_updated+rows_deleted AS changes from sys.x\\$schema_index_statistics ORDER BY rows_inserted+rows_updated+rows_deleted DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 16:14:52 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-24 09:21:56 +00:00
2016-10-10 16:18:26 +00:00
# TOP 15 high read latency index
2022-06-15 12:43:18 +00:00
subheaderprint "Performance schema: Top 15 high read latency index" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select table_schema, table_name,index_name, select_latency from sys.x\\$schema_index_statistics ORDER BY select_latency DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 16:14:52 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 14:00:15 +00:00
2016-10-10 16:18:26 +00:00
# TOP 15 high insert latency index
2022-06-15 12:43:18 +00:00
subheaderprint "Performance schema: Top 15 most modified indexes" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select table_schema, table_name,index_name, insert_latency from sys.x\\$schema_index_statistics ORDER BY insert_latency DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 16:14:52 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 14:54:45 +00:00
2016-10-10 16:18:26 +00:00
# TOP 15 high update latency index
2022-06-15 12:43:18 +00:00
subheaderprint "Performance schema: Top 15 high update latency index" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select table_schema, table_name,index_name, update_latency from sys.x\\$schema_index_statistics ORDER BY update_latency DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 13:34:29 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 13:34:29 +00:00
2016-10-10 16:18:26 +00:00
# TOP 15 high delete latency index
2022-06-15 12:43:18 +00:00
subheaderprint "Performance schema: Top 15 high delete latency index" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select table_schema, table_name,index_name, delete_latency from sys.x\\$schema_index_statistics ORDER BY delete_latency DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 13:34:29 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 13:34:29 +00:00
2016-10-10 16:39:56 +00:00
# TOP 15 most read tables
2022-06-30 12:46:54 +00:00
subheaderprint "Performance schema: Top 15 most read tables" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select table_schema, table_name, rows_fetched from sys.x\\$schema_table_statistics ORDER BY ROWs_fetched DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 13:34:29 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 13:34:29 +00:00
2016-10-10 16:39:56 +00:00
# TOP 15 most used tables
2022-06-15 12:43:18 +00:00
subheaderprint "Performance schema: Top 15 most modified tables" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select table_schema, table_name, rows_inserted+rows_updated+rows_deleted AS changes from sys.x\\$schema_table_statistics ORDER BY rows_inserted+rows_updated+rows_deleted DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 16:39:56 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-24 09:21:56 +00:00
2016-10-10 16:39:56 +00:00
# TOP 15 high read latency tables
2022-06-15 12:43:18 +00:00
subheaderprint "Performance schema: Top 15 high read latency tables" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select table_schema, table_name, fetch_latency from sys.x\\$schema_table_statistics ORDER BY fetch_latency DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 16:39:56 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 16:39:56 +00:00
# TOP 15 high insert latency tables
2022-06-15 12:43:18 +00:00
subheaderprint "Performance schema: Top 15 high insert latency tables" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select table_schema, table_name, insert_latency from sys.x\\$schema_table_statistics ORDER BY insert_latency DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 16:39:56 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 16:39:56 +00:00
# TOP 15 high update latency tables
2022-06-15 12:43:18 +00:00
subheaderprint "Performance schema: Top 15 high update latency tables" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select table_schema, table_name, update_latency from sys.x\\$schema_table_statistics ORDER BY update_latency DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 16:39:56 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 16:39:56 +00:00
# TOP 15 high delete latency tables
2022-06-15 12:43:18 +00:00
subheaderprint "Performance schema: Top 15 high delete latency tables" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select table_schema, table_name, delete_latency from sys.x\\$schema_table_statistics ORDER BY delete_latency DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 13:34:29 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 13:34:29 +00:00
2016-10-10 17:03:40 +00:00
# Redundant indexes
subheaderprint "Performance schema: Redundant indexes" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array ( 'use sys;select * from schema_redundant_indexes;' ) )
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 13:34:29 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 13:34:29 +00:00
2016-11-03 09:36:59 +00:00
subheaderprint "Performance schema: Table not using InnoDB buffer" ;
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
' Select table_schema, table_name from sys.x\\$schema_table_statistics_with_buffer where innodb_buffer_allocated IS NULL;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-17 15:04:10 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 17:03:40 +00:00
2016-10-23 16:32:48 +00:00
subheaderprint "Performance schema: Top 15 Tables using InnoDB buffer" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select table_schema,table_name,innodb_buffer_allocated from sys.x\\$schema_table_statistics_with_buffer where innodb_buffer_allocated IS NOT NULL ORDER BY innodb_buffer_allocated DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 13:34:29 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 17:03:40 +00:00
2016-10-23 16:32:48 +00:00
subheaderprint "Performance schema: Top 15 Tables with InnoDB buffer free" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select table_schema,table_name,innodb_buffer_free from sys.x\\$schema_table_statistics_with_buffer where innodb_buffer_allocated IS NOT NULL ORDER BY innodb_buffer_free DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 13:34:29 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-17 15:04:10 +00:00
2016-11-03 09:36:59 +00:00
subheaderprint "Performance schema: Top 15 Most executed queries" ;
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'select db, LEFT(query, 120), exec_count from sys.x\\$statement_analysis order by exec_count DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-17 15:04:10 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-17 15:04:10 +00:00
2016-11-03 09:36:59 +00:00
subheaderprint
"Performance schema: Latest SQL queries in errors or warnings" ;
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'select LEFT(query, 120), last_seen from sys.x\\$statements_with_errors_or_warnings ORDER BY last_seen LIMIT 40;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 13:34:29 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 16:39:56 +00:00
2016-11-03 09:36:59 +00:00
subheaderprint "Performance schema: Top 20 queries with full table scans" ;
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'select db, LEFT(query, 120), exec_count from sys.x\\$statements_with_full_table_scans order BY exec_count DESC LIMIT 20;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 13:34:29 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 17:03:40 +00:00
2016-11-03 09:36:59 +00:00
subheaderprint "Performance schema: Last 50 queries with full table scans" ;
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'select db, LEFT(query, 120), last_seen from sys.x\\$statements_with_full_table_scans order BY last_seen DESC LIMIT 50;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-17 15:04:10 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 17:03:40 +00:00
2022-06-30 12:46:54 +00:00
subheaderprint "Performance schema: Top 15 reader queries (95% percentile)" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'use sys;select db, LEFT(query, 120), rows_sent from sys.x\\$statements_with_runtimes_in_95th_percentile ORDER BY ROWs_sent DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-17 15:04:10 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 17:03:40 +00:00
2016-11-03 09:36:59 +00:00
subheaderprint
2022-06-30 12:46:54 +00:00
"Performance schema: Top 15 most row look queries (95% percentile)" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'use sys;select db, LEFT(query, 120), rows_examined AS search from sys.x\\$statements_with_runtimes_in_95th_percentile ORDER BY rows_examined DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-17 15:04:10 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-24 09:21:56 +00:00
2016-11-03 09:36:59 +00:00
subheaderprint
2022-06-30 12:46:54 +00:00
"Performance schema: Top 15 total latency queries (95% percentile)" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'use sys;select db, LEFT(query, 120), total_latency AS search from sys.x\\$statements_with_runtimes_in_95th_percentile ORDER BY total_latency DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 13:34:29 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 16:39:56 +00:00
2016-11-03 09:36:59 +00:00
subheaderprint
2022-06-30 12:46:54 +00:00
"Performance schema: Top 15 max latency queries (95% percentile)" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'use sys;select db, LEFT(query, 120), max_latency AS search from sys.x\\$statements_with_runtimes_in_95th_percentile ORDER BY max_latency DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-17 15:04:10 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-24 09:21:56 +00:00
2016-11-03 09:36:59 +00:00
subheaderprint
2022-06-30 12:46:54 +00:00
"Performance schema: Top 15 average latency queries (95% percentile)" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'use sys;select db, LEFT(query, 120), avg_latency AS search from sys.x\\$statements_with_runtimes_in_95th_percentile ORDER BY avg_latency DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-17 15:04:10 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-24 09:21:56 +00:00
2016-11-03 09:36:59 +00:00
subheaderprint "Performance schema: Top 20 queries with sort" ;
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'select db, LEFT(query, 120), exec_count from sys.x\\$statements_with_sorting order BY exec_count DESC LIMIT 20;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-17 15:04:10 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-17 15:04:10 +00:00
2016-11-03 09:36:59 +00:00
subheaderprint "Performance schema: Last 50 queries with sort" ;
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'select db, LEFT(query, 120), last_seen from sys.x\\$statements_with_sorting order BY last_seen DESC LIMIT 50;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-17 15:04:10 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-17 15:04:10 +00:00
2022-06-30 12:46:54 +00:00
subheaderprint "Performance schema: Top 15 row sorting queries with sort" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'use sys;select db, LEFT(query, 120), rows_sorted from sys.x\\$statements_with_sorting ORDER BY ROWs_sorted DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-17 15:04:10 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-17 15:04:10 +00:00
2022-06-30 12:46:54 +00:00
subheaderprint "Performance schema: Top 15 total latency queries with sort" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'use sys;select db, LEFT(query, 120), total_latency AS search from sys.x\\$statements_with_sorting ORDER BY total_latency DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-17 15:04:10 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-17 15:04:10 +00:00
2022-06-30 12:46:54 +00:00
subheaderprint "Performance schema: Top 15 merge queries with sort" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'use sys;select db, LEFT(query, 120), sort_merge_passes AS search from sys.x\\$statements_with_sorting ORDER BY sort_merge_passes DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-17 15:04:10 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-24 09:21:56 +00:00
2016-11-03 09:36:59 +00:00
subheaderprint
2022-06-30 12:46:54 +00:00
"Performance schema: Top 15 average sort merges queries with sort" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'select db, LEFT(query, 120), avg_sort_merges AS search from sys.x\\$statements_with_sorting ORDER BY avg_sort_merges DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-17 15:04:10 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-24 09:21:56 +00:00
2022-06-30 12:46:54 +00:00
subheaderprint "Performance schema: Top 15 scans queries with sort" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'use sys;select db, LEFT(query, 120), sorts_using_scans AS search from sys.x\\$statements_with_sorting ORDER BY sorts_using_scans DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-17 15:04:10 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-17 15:04:10 +00:00
2022-06-30 12:46:54 +00:00
subheaderprint "Performance schema: Top 15 range queries with sort" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'use sys;select db, LEFT(query, 120), sort_using_range AS search from sys.x\\$statements_with_sorting ORDER BY sort_using_range DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-17 15:04:10 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-18 12:55:13 +00:00
2016-10-10 16:39:56 +00:00
##################################################################################
2016-11-03 09:36:59 +00:00
#statements_with_temp_tables
2016-10-10 17:03:40 +00:00
#mysql> desc statements_with_temp_tables;
#+--------------------------+---------------------+------+-----+---------------------+-------+
#| Field | Type | Null | Key | Default | Extra |
#+--------------------------+---------------------+------+-----+---------------------+-------+
#| query | longtext | YES | | NULL | |
#| db | varchar(64) | YES | | NULL | |
#| exec_count | bigint(20) unsigned | NO | | NULL | |
#| total_latency | text | YES | | NULL | |
#| memory_tmp_tables | bigint(20) unsigned | NO | | NULL | |
#| disk_tmp_tables | bigint(20) unsigned | NO | | NULL | |
#| avg_tmp_tables_per_query | decimal(21,0) | NO | | 0 | |
#| tmp_tables_to_disk_pct | decimal(24,0) | NO | | 0 | |
#| first_seen | timestamp | NO | | 0000-00-00 00:00:00 | |
#| last_seen | timestamp | NO | | 0000-00-00 00:00:00 | |
#| digest | varchar(32) | YES | | NULL | |
#+--------------------------+---------------------+------+-----+---------------------+-------+
#11 rows in set (0,01 sec)#
#
2016-11-03 09:36:59 +00:00
subheaderprint "Performance schema: Top 20 queries with temp table" ;
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'select db, LEFT(query, 120), exec_count from sys.x\\$statements_with_temp_tables order BY exec_count DESC LIMIT 20;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 13:34:29 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 16:39:56 +00:00
2016-11-03 09:36:59 +00:00
subheaderprint "Performance schema: Last 50 queries with temp table" ;
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'select db, LEFT(query, 120), last_seen from sys.x\\$statements_with_temp_tables order BY last_seen DESC LIMIT 50;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-18 12:55:13 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-18 12:55:13 +00:00
2016-11-03 09:36:59 +00:00
subheaderprint
2022-06-30 12:46:54 +00:00
"Performance schema: Top 15 total latency queries with temp table" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'select db, LEFT(query, 120), total_latency AS search from sys.x\\$statements_with_temp_tables ORDER BY total_latency DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-18 12:55:13 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-18 12:55:13 +00:00
2022-06-30 12:46:54 +00:00
subheaderprint "Performance schema: Top 15 queries with temp table to disk" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2019-10-01 22:07:46 +00:00
'use sys;select db, LEFT(query, 120), disk_tmp_tables from sys.x\\$statements_with_temp_tables ORDER BY disk_tmp_tables DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 13:34:29 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 16:39:56 +00:00
##################################################################################
2016-11-03 09:36:59 +00:00
#wait_classes_global_by_latency
2016-10-10 17:03:40 +00:00
2022-06-30 12:46:54 +00:00
#mysql> select * from wait_classes_global_by_latency;
2016-10-10 17:03:40 +00:00
#-----------------+-------+---------------+-------------+-------------+-------------+
# event_class | total | total_latency | min_latency | avg_latency | max_latency |
#-----------------+-------+---------------+-------------+-------------+-------------+
# wait/io/file | 15381 | 1.23 s | 0 ps | 80.12 us | 230.64 ms |
# wait/io/table | 59 | 7.57 ms | 5.45 us | 128.24 us | 3.95 ms |
# wait/lock/table | 69 | 3.22 ms | 658.84 ns | 46.64 us | 1.10 ms |
#-----------------+-------+---------------+-------------+-------------+-------------+
# rows in set (0,00 sec)
2022-06-30 12:46:54 +00:00
subheaderprint "Performance schema: Top 15 class events by number" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select event_class, total from sys.x\\$wait_classes_global_by_latency ORDER BY total DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 13:34:29 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 17:03:40 +00:00
2022-06-30 12:46:54 +00:00
subheaderprint "Performance schema: Top 30 events by number" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select events, total from sys.x\\$waits_global_by_latency ORDER BY total DESC LIMIT 30;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 13:34:29 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 16:39:56 +00:00
2022-06-30 12:46:54 +00:00
subheaderprint "Performance schema: Top 15 class events by total latency" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select event_class, total_latency from sys.x\\$wait_classes_global_by_latency ORDER BY total_latency DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 13:34:29 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-18 12:55:13 +00:00
2022-06-30 12:46:54 +00:00
subheaderprint "Performance schema: Top 30 events by total latency" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'use sys;select events, total_latency from sys.x\\$waits_global_by_latency ORDER BY total_latency DESC LIMIT 30;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-18 12:55:13 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-18 12:55:13 +00:00
2022-06-30 12:46:54 +00:00
subheaderprint "Performance schema: Top 15 class events by max latency" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select event_class, max_latency from sys.x\\$wait_classes_global_by_latency ORDER BY max_latency DESC LIMIT 15;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-18 12:55:13 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-18 12:55:13 +00:00
2022-06-30 12:46:54 +00:00
subheaderprint "Performance schema: Top 30 events by max latency" ;
2016-11-03 09:36:59 +00:00
$ nbL = 1 ;
for my $ lQuery (
select_array (
2018-02-22 17:42:32 +00:00
'select events, max_latency from sys.x\\$waits_global_by_latency ORDER BY max_latency DESC LIMIT 30;'
2016-11-03 09:36:59 +00:00
)
)
{
infoprint " +-- $nbL: $lQuery" ;
$ nbL + + ;
2016-10-10 13:34:29 +00:00
}
2018-02-18 04:43:14 +00:00
infoprint "No information found or indicators deactivated."
2016-11-03 09:36:59 +00:00
if ( $ nbL == 1 ) ;
2016-10-10 13:34:29 +00:00
2016-03-16 17:40:44 +00:00
}
2021-01-27 04:09:41 +00:00
# Recommendations for Aria Engine
sub mariadb_aria {
subheaderprint "Aria Metrics" ;
2015-08-19 12:45:24 +00:00
2021-01-27 04:09:41 +00:00
# Aria
2021-02-05 14:25:09 +00:00
if ( ! defined $ myvar { 'have_aria' } ) {
2021-01-27 04:09:41 +00:00
infoprint "Aria Storage Engine not available." ;
return ;
}
2021-02-05 14:25:09 +00:00
if ( $ myvar { 'have_aria' } ne "YES" ) {
2021-01-27 04:09:41 +00:00
infoprint "Aria Storage Engine is disabled." ;
2015-08-19 12:45:24 +00:00
return ;
}
2021-01-27 04:09:41 +00:00
infoprint "Aria Storage Engine is enabled." ;
2015-08-19 12:45:24 +00:00
# Aria pagecache
2021-01-27 04:09:41 +00:00
if ( ! defined ( $ mycalc { 'total_aria_indexes' } ) ) {
2015-08-19 12:45:24 +00:00
push ( @ generalrec ,
2021-01-27 04:09:41 +00:00
"Unable to calculate Aria index size on MySQL server" ) ;
2015-08-19 12:45:24 +00:00
}
else {
if (
$ myvar { 'aria_pagecache_buffer_size' } < $ mycalc { 'total_aria_indexes' }
&& $ mycalc { 'pct_aria_keys_from_mem' } < 95 )
{
badprint "Aria pagecache size / total Aria indexes: "
. hr_bytes ( $ myvar { 'aria_pagecache_buffer_size' } ) . "/"
. hr_bytes ( $ mycalc { 'total_aria_indexes' } ) . "" ;
push ( @ adjvars ,
"aria_pagecache_buffer_size (> "
. hr_bytes ( $ mycalc { 'total_aria_indexes' } )
. ")" ) ;
}
else {
goodprint "Aria pagecache size / total Aria indexes: "
. hr_bytes ( $ myvar { 'aria_pagecache_buffer_size' } ) . "/"
. hr_bytes ( $ mycalc { 'total_aria_indexes' } ) . "" ;
}
if ( $ mystat { 'Aria_pagecache_read_requests' } > 0 ) {
if ( $ mycalc { 'pct_aria_keys_from_mem' } < 95 ) {
badprint
"Aria pagecache hit rate: $mycalc{'pct_aria_keys_from_mem'}% ("
. hr_num ( $ mystat { 'Aria_pagecache_read_requests' } )
. " cached / "
. hr_num ( $ mystat { 'Aria_pagecache_reads' } )
. " reads)" ;
}
else {
goodprint
"Aria pagecache hit rate: $mycalc{'pct_aria_keys_from_mem'}% ("
. hr_num ( $ mystat { 'Aria_pagecache_read_requests' } )
. " cached / "
. hr_num ( $ mystat { 'Aria_pagecache_reads' } )
. " reads)" ;
}
}
else {
# No queries have run that would use keys
}
}
2015-06-18 08:56:47 +00:00
}
2015-08-19 12:45:24 +00:00
2016-01-27 13:50:29 +00:00
# Recommendations for TokuDB
sub mariadb_tokudb {
2016-04-11 10:01:01 +00:00
subheaderprint "TokuDB Metrics" ;
2016-01-27 13:50:29 +00:00
# AriaDB
unless ( defined $ myvar { 'have_tokudb' }
2016-06-10 08:27:55 +00:00
&& $ myvar { 'have_tokudb' } eq "YES" )
2016-01-27 13:50:29 +00:00
{
infoprint "TokuDB is disabled." ;
return ;
}
infoprint "TokuDB is enabled." ;
2022-10-05 08:16:42 +00:00
# Not implemented
2016-01-27 13:50:29 +00:00
}
2016-10-10 13:34:29 +00:00
# Recommendations for XtraDB
sub mariadb_xtradb {
subheaderprint "XtraDB Metrics" ;
# XtraDB
unless ( defined $ myvar { 'have_xtradb' }
&& $ myvar { 'have_xtradb' } eq "YES" )
{
infoprint "XtraDB is disabled." ;
return ;
}
infoprint "XtraDB is enabled." ;
2017-05-19 07:36:33 +00:00
infoprint "Note that MariaDB 10.2 makes use of InnoDB, not XtraDB."
2017-07-05 09:51:33 +00:00
2022-10-05 08:16:42 +00:00
# Not implemented
2016-10-10 13:34:29 +00:00
}
2016-11-03 09:36:59 +00:00
2016-10-10 13:34:29 +00:00
# Recommendations for RocksDB
sub mariadb_rockdb {
subheaderprint "RocksDB Metrics" ;
# RocksDB
unless ( defined $ myvar { 'have_rocksdb' }
&& $ myvar { 'have_rocksdb' } eq "YES" )
{
infoprint "RocksDB is disabled." ;
return ;
}
infoprint "RocksDB is enabled." ;
2022-10-05 08:16:42 +00:00
# Not implemented
2016-10-10 13:34:29 +00:00
}
2016-11-03 09:36:59 +00:00
2016-10-10 13:34:29 +00:00
# Recommendations for Spider
sub mariadb_spider {
subheaderprint "Spider Metrics" ;
# Spider
unless ( defined $ myvar { 'have_spider' }
&& $ myvar { 'have_spider' } eq "YES" )
{
infoprint "Spider is disabled." ;
return ;
}
infoprint "Spider is enabled." ;
2022-10-05 08:16:42 +00:00
# Not implemented
2016-10-10 13:34:29 +00:00
}
2016-11-03 09:36:59 +00:00
2016-10-10 13:34:29 +00:00
# Recommendations for Connect
sub mariadb_connect {
subheaderprint "Connect Metrics" ;
# Connect
unless ( defined $ myvar { 'have_connect' }
&& $ myvar { 'have_connect' } eq "YES" )
{
infoprint "Connect is disabled." ;
return ;
}
2018-08-06 12:53:12 +00:00
infoprint "Connect is enabled." ;
2016-10-10 13:34:29 +00:00
2022-10-05 08:16:42 +00:00
# Not implemented
2016-10-10 13:34:29 +00:00
}
2016-04-04 15:23:43 +00:00
# Perl trim function to remove whitespace from the start and end of the string
sub trim {
2016-04-19 14:19:31 +00:00
my $ string = shift ;
2018-04-04 13:20:27 +00:00
return "" unless defined ( $ string ) ;
2016-04-19 14:19:31 +00:00
$ string =~ s/^\s+// ;
$ string =~ s/\s+$// ;
return $ string ;
2016-04-04 15:23:43 +00:00
}
2016-04-05 16:25:20 +00:00
sub get_wsrep_options {
2016-04-19 14:19:31 +00:00
return ( ) unless defined $ myvar { 'wsrep_provider_options' } ;
2016-04-05 16:25:20 +00:00
2021-08-25 10:01:28 +00:00
my @ galera_options = split /;/ , $ myvar { 'wsrep_provider_options' } ;
2017-07-10 13:57:15 +00:00
my $ wsrep_slave_threads = $ myvar { 'wsrep_slave_threads' } ;
2018-01-10 14:14:19 +00:00
push @ galera_options , ' wsrep_slave_threads = ' . $ wsrep_slave_threads ;
2016-08-30 15:20:56 +00:00
@ galera_options = remove_cr @ galera_options ;
2016-04-19 14:19:31 +00:00
@ galera_options = remove_empty @ galera_options ;
2021-10-15 11:56:27 +00:00
2023-06-22 13:15:25 +00:00
#debugprint Dumper( \@galera_options ) if $opt{debug};
2016-04-05 16:25:20 +00:00
return @ galera_options ;
}
2016-04-19 14:19:31 +00:00
2016-04-05 16:25:20 +00:00
sub get_gcache_memory {
2017-02-07 05:56:17 +00:00
my $ gCacheMem = hr_raw ( get_wsrep_option ( 'gcache.size' ) ) ;
2016-04-18 08:59:50 +00:00
return 0 unless defined $ gCacheMem and $ gCacheMem ne '' ;
return $ gCacheMem ;
2016-04-15 14:17:56 +00:00
}
2016-04-19 14:19:31 +00:00
2016-04-15 14:17:56 +00:00
sub get_wsrep_option {
2016-04-19 14:19:31 +00:00
my $ key = shift ;
return '' unless defined $ myvar { 'wsrep_provider_options' } ;
my @ galera_options = get_wsrep_options ;
return '' unless scalar ( @ galera_options ) > 0 ;
my @ memValues = grep /\s*$key =/ , @ galera_options ;
2021-08-25 10:01:28 +00:00
my $ memValue = $ memValues [ 0 ] ;
2017-03-06 14:17:43 +00:00
return 0 unless defined $ memValue ;
2016-04-15 14:17:56 +00:00
$ memValue =~ s/.*=\s*(.+)$/$1/g ;
2016-04-05 16:25:20 +00:00
return $ memValue ;
}
2016-04-15 14:17:56 +00:00
2023-06-22 21:00:28 +00:00
# REcommendations for Tables
sub mysql_table_structures {
2023-08-16 05:38:34 +00:00
return 0 unless ( $ opt { structstat } > 0 ) ;
2023-06-22 21:00:28 +00:00
subheaderprint "Table structures analysis" ;
my @ primaryKeysNbTables = select_array (
" Select CONCAT ( c . table_schema , ',' , c . table_name )
from information_schema . columns c
join information_schema . tables t using ( TABLE_SCHEMA , TABLE_NAME )
where c . table_schema not in ( 'sys' , 'mysql' , 'information_schema' , 'performance_schema' )
and t . table_type = 'BASE TABLE'
group by c . table_schema , c . table_name
having sum ( if ( c . column_key in ( 'PRI' , 'UNI' ) , 1 , 0 ) ) = 0 "
) ;
2023-07-06 06:19:29 +00:00
my $ tmpContent = 'Schema,Table' ;
2023-06-22 21:00:28 +00:00
if ( scalar ( @ primaryKeysNbTables ) > 0 ) {
badprint "Following table(s) don't have primary key:" ;
foreach my $ badtable ( @ primaryKeysNbTables ) {
badprint "\t$badtable" ;
push @ { $ result { 'Tables without PK' } } , $ badtable ;
2023-07-06 06:19:29 +00:00
$ tmpContent . = "\n$badtable" ;
2023-06-22 21:00:28 +00:00
}
push @ generalrec ,
2023-07-06 06:19:29 +00:00
"Ensure that all table(s) get an explicit primary keys for performance, maintenance and also for replication" ;
2023-06-22 21:00:28 +00:00
}
else {
goodprint "All tables get a primary key" ;
}
dump_into_file ( "tables_without_primary_keys.csv" , $ tmpContent ) ;
my @ nonInnoDBTables = select_array (
2023-07-06 06:19:29 +00:00
" select CONCAT ( table_schema , ',' , table_name , ',' , ENGINE )
2023-06-22 21:00:28 +00:00
FROM information_schema . tables t
WHERE ENGINE < > 'InnoDB'
and t . table_type = 'BASE TABLE'
and table_schema not in
( 'sys' , 'mysql' , 'performance_schema' , 'information_schema' ) "
) ;
2023-07-06 06:19:29 +00:00
$ tmpContent = 'Schema,Table,Engine' ;
2023-06-22 21:00:28 +00:00
if ( scalar ( @ nonInnoDBTables ) > 0 ) {
badprint "Following table(s) are not InnoDB table:" ;
push @ generalrec ,
2023-07-06 06:19:29 +00:00
"Ensure that all table(s) are InnoDB tables for performance and also for replication" ;
2023-06-22 21:00:28 +00:00
foreach my $ badtable ( @ nonInnoDBTables ) {
2023-06-26 18:18:29 +00:00
if ( $ badtable =~ /Memory/i ) {
2023-07-06 06:19:29 +00:00
badprint
"Table $badtable is a MEMORY table. It's suggested to use only InnoDB tables in production" ;
}
else {
badprint "\t$badtable" ;
2023-06-26 18:18:29 +00:00
}
2023-07-06 06:19:29 +00:00
$ tmpContent . = "\n$badtable" ;
2023-06-22 21:00:28 +00:00
}
2023-07-06 06:19:29 +00:00
}
else {
2023-06-22 21:00:28 +00:00
goodprint "All tables are InnoDB tables" ;
}
dump_into_file ( "tables_non_innodb.csv" , $ tmpContent ) ;
my @ nonutf8columns = select_array (
" SELECT CONCAT ( table_schema , ',' , table_name , ',' , column_name , ',' , CHARacter_set_name , ',' , COLLATION_name , ',' , data_type , ',' , CHARACTER_MAXIMUM_LENGTH )
from information_schema . columns
WHERE table_schema not in ( 'sys' , 'mysql' , 'performance_schema' , 'information_schema' )
and ( CHARacter_set_name NOT LIKE 'utf8%'
or COLLATION_name NOT LIKE 'utf8%' ) ; "
) ;
2023-07-06 06:19:29 +00:00
$ tmpContent =
'Schema,Table,Column, Charset, Collation, Data Type, Max Length' ;
2023-06-22 21:00:28 +00:00
if ( scalar ( @ nonutf8columns ) > 0 ) {
badprint "Following character columns(s) are not utf8 compliant:" ;
push @ generalrec ,
2023-07-06 06:19:29 +00:00
"Ensure that all text colums(s) are UTF-8 compliant for encoding support and performance" ;
2023-06-22 21:00:28 +00:00
foreach my $ badtable ( @ nonutf8columns ) {
badprint "\t$badtable" ;
2023-07-06 06:19:29 +00:00
$ tmpContent . = "\n$badtable" ;
2023-06-22 21:00:28 +00:00
}
}
else {
goodprint "All columns are UTF-8 compliant" ;
}
dump_into_file ( "columns_non_utf8.csv" , $ tmpContent ) ;
2023-07-06 06:19:29 +00:00
my @ utf8columns = select_array (
2023-06-22 21:00:28 +00:00
" SELECT CONCAT ( table_schema , ',' , table_name , ',' , column_name , ',' , CHARacter_set_name , ',' , COLLATION_name , ',' , data_type , ',' , CHARACTER_MAXIMUM_LENGTH )
from information_schema . columns
WHERE table_schema not in ( 'sys' , 'mysql' , 'performance_schema' , 'information_schema' )
and ( CHARacter_set_name LIKE 'utf8%'
or COLLATION_name LIKE 'utf8%' ) ; "
) ;
2023-07-06 06:19:29 +00:00
$ tmpContent =
'Schema,Table,Column, Charset, Collation, Data Type, Max Length' ;
2023-06-22 21:00:28 +00:00
foreach my $ badtable ( @ utf8columns ) {
2023-07-06 06:19:29 +00:00
$ tmpContent . = "\n$badtable" ;
}
2023-06-22 21:00:28 +00:00
dump_into_file ( "columns_utf8.csv" , $ tmpContent ) ;
2023-07-06 06:19:29 +00:00
my @ ftcolumns = select_array (
2023-06-26 18:18:29 +00:00
" SELECT CONCAT ( table_schema , ',' , table_name , ',' , column_name , ',' , data_type )
from information_schema . columns
WHERE table_schema not in ( 'sys' , 'mysql' , 'performance_schema' , 'information_schema' )
AND data_type = 'FULLTEXT' ; "
) ;
2023-07-06 06:19:29 +00:00
$ tmpContent = 'Schema,Table,Column, Data Type' ;
2023-06-26 18:18:29 +00:00
foreach my $ ctable ( @ ftcolumns ) {
2023-07-06 06:19:29 +00:00
$ tmpContent . = "\n$ctable" ;
}
2023-06-26 18:18:29 +00:00
dump_into_file ( "fulltext_columns.csv" , $ tmpContent ) ;
2023-06-22 21:00:28 +00:00
}
2023-07-06 06:19:29 +00:00
2016-01-27 13:50:29 +00:00
# Recommendations for Galera
sub mariadb_galera {
2016-04-11 10:01:01 +00:00
subheaderprint "Galera Metrics" ;
2016-01-27 13:50:29 +00:00
2016-04-05 16:25:20 +00:00
# Galera Cluster
2016-01-27 13:50:29 +00:00
unless ( defined $ myvar { 'have_galera' }
2016-04-04 15:23:43 +00:00
&& $ myvar { 'have_galera' } eq "YES" )
2016-01-27 13:50:29 +00:00
{
infoprint "Galera is disabled." ;
return ;
}
infoprint "Galera is enabled." ;
2016-04-19 14:19:31 +00:00
debugprint "Galera variables:" ;
2016-04-04 15:30:16 +00:00
foreach my $ gvar ( keys % myvar ) {
2016-04-19 14:19:31 +00:00
next unless $ gvar =~ /^wsrep.*/ ;
next if $ gvar eq 'wsrep_provider_options' ;
debugprint "\t" . trim ( $ gvar ) . " = " . $ myvar { $ gvar } ;
2016-08-31 08:30:20 +00:00
$ result { 'Galera' } { 'variables' } { $ gvar } = $ myvar { $ gvar } ;
2016-04-04 15:30:16 +00:00
}
2018-11-26 13:41:36 +00:00
if ( not defined ( $ myvar { 'wsrep_on' } ) or $ myvar { 'wsrep_on' } ne "ON" ) {
infoprint "Galera is disabled." ;
return ;
}
2016-04-19 14:19:31 +00:00
debugprint "Galera wsrep provider Options:" ;
my @ galera_options = get_wsrep_options ;
2016-08-31 08:30:20 +00:00
$ result { 'Galera' } { 'wsrep options' } = get_wsrep_options ( ) ;
2016-04-19 14:19:31 +00:00
foreach my $ gparam ( @ galera_options ) {
debugprint "\t" . trim ( $ gparam ) ;
2016-04-04 15:23:43 +00:00
}
2016-04-19 14:19:31 +00:00
debugprint "Galera status:" ;
2016-04-04 15:23:43 +00:00
foreach my $ gstatus ( keys % mystat ) {
2016-04-19 14:19:31 +00:00
next unless $ gstatus =~ /^wsrep.*/ ;
debugprint "\t" . trim ( $ gstatus ) . " = " . $ mystat { $ gstatus } ;
2016-08-31 08:30:20 +00:00
$ result { 'Galera' } { 'status' } { $ gstatus } = $ myvar { $ gstatus } ;
2016-04-19 14:19:31 +00:00
}
infoprint "GCache is using "
. hr_bytes_rnd ( get_wsrep_option ( 'gcache.mem_size' ) ) ;
2018-11-26 12:57:11 +00:00
2022-06-30 12:46:54 +00:00
infoprint "CPU cores detected : " . ( cpu_cores ) ;
2018-11-26 12:57:11 +00:00
infoprint "wsrep_slave_threads: " . get_wsrep_option ( 'wsrep_slave_threads' ) ;
2021-03-08 17:01:44 +00:00
2018-11-26 12:57:11 +00:00
if ( get_wsrep_option ( 'wsrep_slave_threads' ) > ( ( cpu_cores ) * 4 )
or get_wsrep_option ( 'wsrep_slave_threads' ) < ( ( cpu_cores ) * 2 ) )
2017-03-06 14:17:43 +00:00
{
badprint
2022-12-29 04:13:02 +00:00
"wsrep_slave_threads is not equal to 2, 3 or 4 times the number of CPU(s)" ;
2018-11-26 12:57:11 +00:00
push @ adjvars , "wsrep_slave_threads = " . ( ( cpu_cores ) * 4 ) ;
2017-03-06 14:17:43 +00:00
}
else {
goodprint
2022-12-29 04:13:02 +00:00
"wsrep_slave_threads is equal to 2, 3 or 4 times the number of CPU(s)" ;
2017-03-06 14:17:43 +00:00
}
2017-02-13 17:08:28 +00:00
2017-07-05 09:51:33 +00:00
if ( get_wsrep_option ( 'wsrep_slave_threads' ) > 1 ) {
infoprint
"wsrep parallel slave can cause frequent inconsistency crash." ;
push @ adjvars ,
2022-12-29 04:13:02 +00:00
"Set wsrep_slave_threads to 1 in case of HA_ERR_FOUND_DUPP_KEY crash on slave" ;
2017-07-05 09:51:33 +00:00
2017-03-07 16:53:36 +00:00
# check options for parallel slave
2017-07-05 09:51:33 +00:00
if ( get_wsrep_option ( 'wsrep_slave_FK_checks' ) eq "OFF" ) {
2017-03-07 16:53:36 +00:00
badprint "wsrep_slave_FK_checks is off with parallel slave" ;
2017-07-05 09:51:33 +00:00
push @ adjvars ,
"wsrep_slave_FK_checks should be ON when using parallel slave" ;
2017-03-07 16:53:36 +00:00
}
2017-07-05 09:51:33 +00:00
2017-03-14 17:21:19 +00:00
# wsrep_slave_UK_checks seems useless in MySQL source code
2017-07-05 09:51:33 +00:00
if ( $ myvar { 'innodb_autoinc_lock_mode' } != 2 ) {
badprint
"innodb_autoinc_lock_mode is incorrect with parallel slave" ;
push @ adjvars ,
"innodb_autoinc_lock_mode should be 2 when using parallel slave" ;
2017-03-07 16:53:36 +00:00
}
}
2017-07-05 09:51:33 +00:00
if ( get_wsrep_option ( 'gcs.fc_limit' ) != $ myvar { 'wsrep_slave_threads' } * 5 )
{
2021-07-02 16:31:21 +00:00
badprint "gcs.fc_limit should be equal to 5 * wsrep_slave_threads (="
. ( $ myvar { 'wsrep_slave_threads' } * 5 ) . ")" ;
push @ adjvars , "gcs.fc_limit= wsrep_slave_threads * 5 (="
. ( $ myvar { 'wsrep_slave_threads' } * 5 ) . ")" ;
2017-07-05 09:51:33 +00:00
}
else {
2021-07-02 16:31:21 +00:00
goodprint "gcs.fc_limit is equal to 5 * wsrep_slave_threads ( ="
. get_wsrep_option ( 'gcs.fc_limit' ) . ")" ;
2017-02-13 17:08:28 +00:00
}
2017-07-05 09:51:33 +00:00
if ( get_wsrep_option ( 'gcs.fc_factor' ) != 0.8 ) {
2021-07-02 16:31:21 +00:00
badprint "gcs.fc_factor should be equal to 0.8 (="
. get_wsrep_option ( 'gcs.fc_factor' ) . ")" ;
2017-02-13 17:08:28 +00:00
push @ adjvars , "gcs.fc_factor=0.8" ;
}
else {
2017-03-08 10:50:02 +00:00
goodprint "gcs.fc_factor is equal to 0.8" ;
2017-02-13 17:08:28 +00:00
}
2017-07-05 09:51:33 +00:00
if ( get_wsrep_option ( 'wsrep_flow_control_paused' ) > 0.02 ) {
2017-02-13 17:08:28 +00:00
badprint "Fraction of time node pause flow control > 0.02" ;
2017-07-05 09:51:33 +00:00
}
else {
goodprint
2022-12-29 04:13:02 +00:00
"Flow control fraction seems to be OK (wsrep_flow_control_paused <= 0.02)" ;
2017-02-13 17:08:28 +00:00
}
2017-03-08 18:18:47 +00:00
2016-04-19 14:19:31 +00:00
if ( $ myvar { 'binlog_format' } ne 'ROW' ) {
badprint "Binlog format should be in ROW mode." ;
push @ adjvars , "binlog_format = ROW" ;
2017-07-05 09:51:33 +00:00
}
else {
2016-04-19 14:19:31 +00:00
goodprint "Binlog format is in ROW mode." ;
}
if ( $ myvar { 'innodb_flush_log_at_trx_commit' } != 0 ) {
2016-10-23 16:32:48 +00:00
badprint "InnoDB flush log at each commit should be disabled." ;
2016-04-19 14:19:31 +00:00
push @ adjvars , "innodb_flush_log_at_trx_commit = 0" ;
2017-07-05 09:51:33 +00:00
}
else {
2016-10-23 16:32:48 +00:00
goodprint "InnoDB flush log at each commit is disabled for Galera." ;
2016-04-19 14:19:31 +00:00
}
infoprint "Read consistency mode :" . $ myvar { 'wsrep_causal_reads' } ;
if ( defined ( $ myvar { 'wsrep_cluster_name' } )
and $ myvar { 'wsrep_on' } eq "ON" )
{
goodprint "Galera WsREP is enabled." ;
if ( defined ( $ myvar { 'wsrep_cluster_address' } )
and trim ( "$myvar{'wsrep_cluster_address'}" ) ne "" )
{
goodprint "Galera Cluster address is defined: "
. $ myvar { 'wsrep_cluster_address' } ;
2016-05-19 15:10:48 +00:00
my @ NodesTmp = split /,/ , $ myvar { 'wsrep_cluster_address' } ;
2021-08-25 10:01:28 +00:00
my $ nbNodes = @ NodesTmp ;
2016-04-27 10:42:50 +00:00
infoprint "There are $nbNodes nodes in wsrep_cluster_address" ;
2016-04-19 14:19:31 +00:00
my $ nbNodesSize = trim ( $ mystat { 'wsrep_cluster_size' } ) ;
2016-04-27 10:42:50 +00:00
if ( $ nbNodesSize == 3 or $ nbNodesSize == 5 ) {
goodprint "There are $nbNodesSize nodes in wsrep_cluster_size." ;
2016-04-19 14:19:31 +00:00
}
else {
badprint
2022-12-29 04:13:02 +00:00
"There are $nbNodesSize nodes in wsrep_cluster_size. Prefer 3 or 5 nodes architecture." ;
2017-01-13 11:23:05 +00:00
push @ generalrec , "Prefer 3 or 5 nodes architecture." ;
2016-04-19 14:19:31 +00:00
}
2016-08-31 08:30:20 +00:00
2016-04-27 10:42:50 +00:00
# wsrep_cluster_address doesn't include garbd nodes
if ( $ nbNodes > $ nbNodesSize ) {
2016-04-19 14:19:31 +00:00
badprint
2022-12-29 04:13:02 +00:00
"All cluster nodes are not detected. wsrep_cluster_size less than node count in wsrep_cluster_address" ;
2016-04-19 14:19:31 +00:00
}
else {
2016-04-27 10:42:50 +00:00
goodprint "All cluster nodes detected." ;
2016-04-19 14:19:31 +00:00
}
}
else {
2016-04-06 08:33:56 +00:00
badprint "Galera Cluster address is undefined" ;
2016-04-19 14:19:31 +00:00
push @ adjvars ,
"set up wsrep_cluster_address variable for Galera replication" ;
}
if ( defined ( $ myvar { 'wsrep_cluster_name' } )
and trim ( $ myvar { 'wsrep_cluster_name' } ) ne "" )
{
goodprint "Galera Cluster name is defined: "
. $ myvar { 'wsrep_cluster_name' } ;
}
else {
badprint "Galera Cluster name is undefined" ;
push @ adjvars ,
"set up wsrep_cluster_name variable for Galera replication" ;
2016-04-06 08:33:56 +00:00
}
2016-04-19 14:19:31 +00:00
if ( defined ( $ myvar { 'wsrep_node_name' } )
and trim ( $ myvar { 'wsrep_node_name' } ) ne "" )
{
goodprint "Galera Node name is defined: "
. $ myvar { 'wsrep_node_name' } ;
2016-04-06 08:33:56 +00:00
}
2016-04-19 14:19:31 +00:00
else {
2016-04-15 14:17:56 +00:00
badprint "Galera node name is undefined" ;
2016-04-19 14:19:31 +00:00
push @ adjvars ,
"set up wsrep_node_name variable for Galera replication" ;
2016-04-15 14:17:56 +00:00
}
2016-04-19 14:19:31 +00:00
if ( trim ( $ myvar { 'wsrep_notify_cmd' } ) ne "" ) {
goodprint "Galera Notify command is defined." ;
2016-04-15 14:17:56 +00:00
}
2016-04-19 14:19:31 +00:00
else {
badprint "Galera Notify command is not defined." ;
2022-12-29 04:13:02 +00:00
push ( @ adjvars ,
"set up parameter wsrep_notify_cmd to be notified" ) ;
2016-04-19 14:19:31 +00:00
}
2018-02-22 14:29:33 +00:00
if ( trim ( $ myvar { 'wsrep_sst_method' } ) !~ "^xtrabackup.*"
and trim ( $ myvar { 'wsrep_sst_method' } ) !~ "^mariabackup" )
{
2016-04-21 07:06:13 +00:00
badprint "Galera SST method is not xtrabackup based." ;
2016-08-31 08:30:20 +00:00
push ( @ adjvars ,
2022-12-29 04:13:02 +00:00
"set up parameter wsrep_sst_method to xtrabackup based parameter"
2016-08-31 08:30:20 +00:00
) ;
2016-04-19 14:19:31 +00:00
}
else {
2016-04-21 21:19:36 +00:00
goodprint "SST Method is based on xtrabackup." ;
2016-04-15 14:17:56 +00:00
}
2016-08-31 08:30:20 +00:00
if (
(
defined ( $ myvar { 'wsrep_OSU_method' } )
&& trim ( $ myvar { 'wsrep_OSU_method' } ) eq "TOI"
)
|| ( defined ( $ myvar { 'wsrep_osu_method' } )
&& trim ( $ myvar { 'wsrep_osu_method' } ) eq "TOI" )
)
{
2016-04-15 14:17:56 +00:00
goodprint "TOI is default mode for upgrade." ;
2016-04-19 14:19:31 +00:00
}
else {
2016-04-15 14:17:56 +00:00
badprint "Schema upgrade are not replicated automatically" ;
2016-04-19 14:19:31 +00:00
push ( @ adjvars , "set up parameter wsrep_OSU_method to TOI" ) ;
}
infoprint "Max WsRep message : "
. hr_bytes ( $ myvar { 'wsrep_max_ws_size' } ) ;
}
else {
badprint "Galera WsREP is disabled" ;
}
if ( defined ( $ mystat { 'wsrep_connected' } )
and $ mystat { 'wsrep_connected' } eq "ON" )
{
goodprint "Node is connected" ;
}
else {
badprint "Node is disconnected" ;
}
if ( defined ( $ mystat { 'wsrep_ready' } ) and $ mystat { 'wsrep_ready' } eq "ON" )
{
2016-04-15 14:17:56 +00:00
goodprint "Node is ready" ;
2016-04-19 14:19:31 +00:00
}
else {
2016-04-15 14:17:56 +00:00
badprint "Node is not ready" ;
2016-04-19 14:19:31 +00:00
}
infoprint "Cluster status :" . $ mystat { 'wsrep_cluster_status' } ;
if ( defined ( $ mystat { 'wsrep_cluster_status' } )
and $ mystat { 'wsrep_cluster_status' } eq "Primary" )
{
2016-04-15 14:17:56 +00:00
goodprint "Galera cluster is consistent and ready for operations" ;
2016-04-19 14:19:31 +00:00
}
else {
2016-04-15 14:17:56 +00:00
badprint "Cluster is not consistent and ready" ;
2016-04-19 14:19:31 +00:00
}
if ( $ mystat { 'wsrep_local_state_uuid' } eq
$ mystat { 'wsrep_cluster_state_uuid' } )
{
goodprint "Node and whole cluster at the same level: "
. $ mystat { 'wsrep_cluster_state_uuid' } ;
}
else {
badprint "Node and whole cluster not the same level" ;
infoprint "Node state uuid: " . $ mystat { 'wsrep_local_state_uuid' } ;
infoprint "Cluster state uuid: " . $ mystat { 'wsrep_cluster_state_uuid' } ;
}
if ( $ mystat { 'wsrep_local_state_comment' } eq 'Synced' ) {
2016-04-15 14:17:56 +00:00
goodprint "Node is synced with whole cluster." ;
2016-04-19 14:19:31 +00:00
}
else {
2016-04-15 14:17:56 +00:00
badprint "Node is not synced" ;
2016-04-19 14:19:31 +00:00
infoprint "Node State : " . $ mystat { 'wsrep_local_state_comment' } ;
}
if ( $ mystat { 'wsrep_local_cert_failures' } == 0 ) {
2016-04-15 14:17:56 +00:00
goodprint "There is no certification failures detected." ;
2016-04-19 14:19:31 +00:00
}
else {
badprint "There is "
. $ mystat { 'wsrep_local_cert_failures' }
. " certification failure(s)detected." ;
}
2016-04-15 14:17:56 +00:00
2016-04-19 14:19:31 +00:00
for my $ key ( keys % mystat ) {
if ( $ key =~ /wsrep_|galera/i ) {
debugprint "WSREP: $key = $mystat{$key}" ;
}
}
2021-10-15 11:56:27 +00:00
2023-06-22 13:15:25 +00:00
#debugprint Dumper get_wsrep_options() if $opt{debug};
2016-01-27 13:50:29 +00:00
}
2015-12-10 10:52:39 +00:00
# Recommendations for InnoDB
2015-06-18 08:56:47 +00:00
sub mysql_innodb {
2016-04-11 10:01:01 +00:00
subheaderprint "InnoDB Metrics" ;
2015-08-19 12:45:24 +00:00
# InnoDB
unless ( defined $ myvar { 'have_innodb' }
2021-02-05 14:25:09 +00:00
&& $ myvar { 'have_innodb' } eq "YES" )
2015-08-19 12:45:24 +00:00
{
infoprint "InnoDB is disabled." ;
if ( mysql_version_ge ( 5 , 5 ) ) {
2021-02-01 00:31:40 +00:00
my $ defengine = 'InnoDB' ;
2021-02-05 14:25:09 +00:00
$ defengine = $ myvar { 'default_storage_engine' }
if defined ( $ myvar { 'default_storage_engine' } ) ;
2015-08-19 12:45:24 +00:00
badprint
2022-12-29 04:13:02 +00:00
"InnoDB Storage engine is disabled. $defengine is the default storage engine"
2021-02-05 14:25:09 +00:00
if $ defengine eq 'InnoDB' ;
2021-02-01 00:31:40 +00:00
infoprint
2022-12-29 04:13:02 +00:00
"InnoDB Storage engine is disabled. $defengine is the default storage engine"
2021-02-05 14:25:09 +00:00
if $ defengine ne 'InnoDB' ;
2015-08-19 12:45:24 +00:00
}
return ;
}
infoprint "InnoDB is enabled." ;
2021-02-05 14:25:09 +00:00
if ( ! defined $ enginestats { 'InnoDB' } ) {
if ( $ opt { skipsize } eq 1 ) {
2021-02-01 00:31:40 +00:00
infoprint "Skipped due to --skipsize option" ;
return ;
}
2021-02-05 14:25:09 +00:00
badprint "No tables are Innodb" ;
2021-02-01 00:31:40 +00:00
$ enginestats { 'InnoDB' } = 0 ;
}
2015-08-19 12:45:24 +00:00
if ( $ opt { buffers } ne 0 ) {
infoprint "InnoDB Buffers" ;
if ( defined $ myvar { 'innodb_buffer_pool_size' } ) {
infoprint " +-- InnoDB Buffer Pool: "
. hr_bytes ( $ myvar { 'innodb_buffer_pool_size' } ) . "" ;
}
if ( defined $ myvar { 'innodb_buffer_pool_instances' } ) {
infoprint " +-- InnoDB Buffer Pool Instances: "
. $ myvar { 'innodb_buffer_pool_instances' } . "" ;
}
2016-08-31 08:30:20 +00:00
2016-08-30 12:38:16 +00:00
if ( defined $ myvar { 'innodb_buffer_pool_chunk_size' } ) {
infoprint " +-- InnoDB Buffer Pool Chunk Size: "
. hr_bytes ( $ myvar { 'innodb_buffer_pool_chunk_size' } ) . "" ;
}
2015-08-19 12:45:24 +00:00
if ( defined $ myvar { 'innodb_additional_mem_pool_size' } ) {
infoprint " +-- InnoDB Additional Mem Pool: "
. hr_bytes ( $ myvar { 'innodb_additional_mem_pool_size' } ) . "" ;
}
2022-12-29 17:36:02 +00:00
if ( defined $ myvar { 'innodb_redo_log_capacity' } ) {
infoprint " +-- InnoDB Redo Log Capacity: "
. hr_bytes ( $ myvar { 'innodb_redo_log_capacity' } ) ;
2023-07-06 06:19:29 +00:00
}
else {
if ( defined $ myvar { 'innodb_log_file_size' } ) {
infoprint " +-- InnoDB Log File Size: "
. hr_bytes ( $ myvar { 'innodb_log_file_size' } ) ;
}
if ( defined $ myvar { 'innodb_log_files_in_group' } ) {
infoprint " +-- InnoDB Log File In Group: "
. $ myvar { 'innodb_log_files_in_group' } ;
infoprint " +-- InnoDB Total Log File Size: "
. hr_bytes ( $ myvar { 'innodb_log_files_in_group' } *
$ myvar { 'innodb_log_file_size' } )
. "("
. $ mycalc { 'innodb_log_size_pct' }
. " % of buffer pool)" ;
}
else {
infoprint " +-- InnoDB Total Log File Size: "
. hr_bytes ( $ myvar { 'innodb_log_file_size' } ) . "("
. $ mycalc { 'innodb_log_size_pct' }
. " % of buffer pool)" ;
}
2016-11-28 16:48:22 +00:00
}
2015-08-19 12:45:24 +00:00
if ( defined $ myvar { 'innodb_log_buffer_size' } ) {
infoprint " +-- InnoDB Log Buffer: "
2016-11-03 09:36:59 +00:00
. hr_bytes ( $ myvar { 'innodb_log_buffer_size' } ) ;
2015-08-19 12:45:24 +00:00
}
if ( defined $ mystat { 'Innodb_buffer_pool_pages_free' } ) {
infoprint " +-- InnoDB Log Buffer Free: "
. hr_bytes ( $ mystat { 'Innodb_buffer_pool_pages_free' } ) . "" ;
}
if ( defined $ mystat { 'Innodb_buffer_pool_pages_total' } ) {
infoprint " +-- InnoDB Log Buffer Used: "
. hr_bytes ( $ mystat { 'Innodb_buffer_pool_pages_total' } ) . "" ;
}
}
2023-06-21 21:40:09 +00:00
2016-11-02 19:02:41 +00:00
if ( defined $ myvar { 'innodb_thread_concurrency' } ) {
2016-11-10 03:29:34 +00:00
infoprint "InnoDB Thread Concurrency: "
2016-11-03 09:36:59 +00:00
. $ myvar { 'innodb_thread_concurrency' } ;
2016-11-02 19:02:41 +00:00
}
2016-11-03 09:36:59 +00:00
2017-09-09 11:22:30 +00:00
# InnoDB Buffer Pool Size
2016-11-02 20:16:54 +00:00
if ( $ myvar { 'innodb_file_per_table' } eq "ON" ) {
2016-11-02 19:02:41 +00:00
goodprint "InnoDB File per table is activated" ;
2023-07-06 06:19:29 +00:00
}
else {
2016-11-02 19:02:41 +00:00
badprint "InnoDB File per table is not activated" ;
2016-11-03 09:36:59 +00:00
push ( @ adjvars , "innodb_file_per_table=ON" ) ;
2016-11-02 19:02:41 +00:00
}
2015-08-19 12:45:24 +00:00
2017-09-09 11:22:30 +00:00
# InnoDB Buffer Pool Size
2023-07-06 06:19:29 +00:00
if ( $ arch == 32 && $ myvar { 'innodb_buffer_pool_size' } > 4294967295 ) {
badprint
2023-07-26 22:23:00 +00:00
"InnoDB Buffer Pool size limit reached for 32 bits architecture: ("
2023-07-06 06:19:29 +00:00
. hr_bytes ( 4294967295 ) . " )" ;
push ( @ adjvars ,
"limit innodb_buffer_pool_size under "
. hr_bytes ( 4294967295 )
. " for 32 bits architecture" ) ;
}
if ( $ arch == 32 && $ myvar { 'innodb_buffer_pool_size' } < 4294967295 ) {
2023-07-26 22:23:00 +00:00
goodprint "InnoDB Buffer Pool size ( "
2023-07-06 06:19:29 +00:00
. hr_bytes ( $ myvar { 'innodb_buffer_pool_size' } )
. " ) under limit for 32 bits architecture: ("
. hr_bytes ( 4294967295 ) . ")" ;
2023-06-22 13:15:25 +00:00
}
2023-07-06 06:19:29 +00:00
if ( $ arch == 64
&& $ myvar { 'innodb_buffer_pool_size' } > 18446744073709551615 )
{
2023-07-26 22:23:00 +00:00
badprint "InnoDB Buffer Pool size limit("
2023-07-06 06:19:29 +00:00
. hr_bytes ( 18446744073709551615 )
. ") reached for 64 bits architecture" ;
push ( @ adjvars ,
"limit innodb_buffer_pool_size under "
. hr_bytes ( 18446744073709551615 )
. " for 64 bits architecture" ) ;
2023-06-22 13:15:25 +00:00
}
2023-07-06 06:19:29 +00:00
if ( $ arch == 64
&& $ myvar { 'innodb_buffer_pool_size' } < 18446744073709551615 )
{
2023-07-26 22:23:00 +00:00
goodprint "InnoDB Buffer Pool size ( "
2023-07-06 06:19:29 +00:00
. hr_bytes ( $ myvar { 'innodb_buffer_pool_size' } )
. " ) under limit for 64 bits architecture: ("
. hr_bytes ( 18446744073709551615 ) . " )" ;
}
2015-08-19 12:45:24 +00:00
if ( $ myvar { 'innodb_buffer_pool_size' } > $ enginestats { 'InnoDB' } ) {
goodprint "InnoDB buffer pool / data size: "
2023-07-06 05:52:19 +00:00
. hr_bytes ( $ myvar { 'innodb_buffer_pool_size' } ) . " / "
2015-08-19 12:45:24 +00:00
. hr_bytes ( $ enginestats { 'InnoDB' } ) . "" ;
2023-07-06 06:19:29 +00:00
}
else {
2015-09-16 16:09:10 +00:00
badprint "InnoDB buffer pool / data size: "
2022-06-30 12:46:54 +00:00
. hr_bytes ( $ myvar { 'innodb_buffer_pool_size' } ) . " / "
2015-08-19 12:45:24 +00:00
. hr_bytes ( $ enginestats { 'InnoDB' } ) . "" ;
push ( @ adjvars ,
"innodb_buffer_pool_size (>= "
2018-07-05 14:48:45 +00:00
. hr_bytes ( $ enginestats { 'InnoDB' } )
2015-08-19 12:45:24 +00:00
. ") if possible." ) ;
}
2016-11-03 09:36:59 +00:00
if ( $ mycalc { 'innodb_log_size_pct' } < 20
or $ mycalc { 'innodb_log_size_pct' } > 30 )
2023-07-06 06:19:29 +00:00
{
2023-06-21 21:40:09 +00:00
if ( defined $ myvar { 'innodb_redo_log_capacity' } ) {
2023-07-06 06:19:29 +00:00
badprint
"Ratio InnoDB redo log capacity / InnoDB Buffer pool size ("
. $ mycalc { 'innodb_log_size_pct' } . "%): "
. hr_bytes ( $ myvar { 'innodb_redo_log_capacity' } ) . " / "
. hr_bytes ( $ myvar { 'innodb_buffer_pool_size' } )
. " should be equal to 25%" ;
push ( @ adjvars ,
"innodb_redo_log_capacity should be (="
. hr_bytes_rnd ( $ myvar { 'innodb_buffer_pool_size' } / 4 )
. ") if possible, so InnoDB Redo log Capacity equals 25% of buffer pool size."
) ;
push ( @ generalrec ,
"Be careful, increasing innodb_redo_log_capacity means higher crash recovery mean time"
) ;
}
else {
badprint "Ratio InnoDB log file size / InnoDB Buffer pool size ("
. $ mycalc { 'innodb_log_size_pct' } . "%): "
. hr_bytes ( $ myvar { 'innodb_log_file_size' } ) . " * "
. $ myvar { 'innodb_log_files_in_group' } . " / "
. hr_bytes ( $ myvar { 'innodb_buffer_pool_size' } )
. " should be equal to 25%" ;
push (
@ adjvars ,
"innodb_log_file_size should be (="
. hr_bytes_rnd (
$ myvar { 'innodb_buffer_pool_size' } /
$ myvar { 'innodb_log_files_in_group' } / 4
)
. ") if possible, so InnoDB total log file size equals 25% of buffer pool size."
) ;
push ( @ generalrec ,
"Be careful, increasing innodb_log_file_size / innodb_log_files_in_group means higher crash recovery mean time"
) ;
}
if ( mysql_version_le ( 5 , 6 , 2 ) ) {
2021-02-05 14:25:09 +00:00
push ( @ generalrec ,
2022-06-30 12:46:54 +00:00
"For MySQL 5.6.2 and lower, total innodb_log_file_size should have a ceiling of (4096MB / log files in group) - 1MB."
2021-02-05 14:25:09 +00:00
) ;
2019-10-03 20:06:51 +00:00
}
2023-06-21 21:40:09 +00:00
2023-07-06 06:19:29 +00:00
}
else {
2023-06-21 21:40:09 +00:00
if ( defined $ myvar { 'innodb_redo_log_capacity' } ) {
2023-07-06 06:19:29 +00:00
goodprint
"Ratio InnoDB Redo Log Capacity / InnoDB Buffer pool size: "
. hr_bytes ( $ myvar { 'innodb_redo_log_capacity' } ) . "/"
. hr_bytes ( $ myvar { 'innodb_buffer_pool_size' } )
. " should be equal to 25%" ;
}
else {
2023-06-21 21:40:09 +00:00
push ( @ generalrec ,
2023-07-06 06:19:29 +00:00
"Before changing innodb_log_file_size and/or innodb_log_files_in_group read this: https://bit.ly/2TcGgtU"
2023-06-21 21:40:09 +00:00
) ;
2023-07-06 06:19:29 +00:00
goodprint "Ratio InnoDB log file size / InnoDB Buffer pool size: "
. hr_bytes ( $ myvar { 'innodb_log_file_size' } ) . " * "
. $ myvar { 'innodb_log_files_in_group' } . "/"
. hr_bytes ( $ myvar { 'innodb_buffer_pool_size' } )
. " should be equal to 25%" ;
2023-06-21 21:40:09 +00:00
}
2016-10-18 12:25:02 +00:00
}
2016-11-03 09:36:59 +00:00
2017-09-09 11:22:30 +00:00
# InnoDB Buffer Pool Instances (MySQL 5.6.6+)
2022-03-28 20:53:31 +00:00
if ( not mysql_version_ge ( 10 , 4 )
2021-02-05 14:25:09 +00:00
and defined ( $ myvar { 'innodb_buffer_pool_instances' } ) )
{
2015-08-19 12:45:24 +00:00
# Bad Value if > 64
if ( $ myvar { 'innodb_buffer_pool_instances' } > 64 ) {
badprint "InnoDB buffer pool instances: "
. $ myvar { 'innodb_buffer_pool_instances' } . "" ;
push ( @ adjvars , "innodb_buffer_pool_instances (<= 64)" ) ;
}
2017-09-09 11:22:30 +00:00
# InnoDB Buffer Pool Size > 1Go
2015-08-19 12:45:24 +00:00
if ( $ myvar { 'innodb_buffer_pool_size' } > 1024 * 1024 * 1024 ) {
2017-09-09 11:22:30 +00:00
# InnoDB Buffer Pool Size / 1Go = InnoDB Buffer Pool Instances limited to 64 max.
2015-08-19 12:45:24 +00:00
2017-09-09 11:22:30 +00:00
# InnoDB Buffer Pool Size > 64Go
2015-08-19 12:45:24 +00:00
my $ max_innodb_buffer_pool_instances =
int ( $ myvar { 'innodb_buffer_pool_size' } / ( 1024 * 1024 * 1024 ) ) ;
$ max_innodb_buffer_pool_instances = 64
if ( $ max_innodb_buffer_pool_instances > 64 ) ;
if ( $ myvar { 'innodb_buffer_pool_instances' } !=
$ max_innodb_buffer_pool_instances )
{
badprint "InnoDB buffer pool instances: "
. $ myvar { 'innodb_buffer_pool_instances' } . "" ;
push ( @ adjvars ,
"innodb_buffer_pool_instances(="
. $ max_innodb_buffer_pool_instances
. ")" ) ;
}
else {
goodprint "InnoDB buffer pool instances: "
. $ myvar { 'innodb_buffer_pool_instances' } . "" ;
}
2021-02-05 14:25:09 +00:00
2017-09-09 11:22:30 +00:00
# InnoDB Buffer Pool Size < 1Go
2015-08-19 12:45:24 +00:00
}
else {
if ( $ myvar { 'innodb_buffer_pool_instances' } != 1 ) {
badprint
2016-10-18 12:25:02 +00:00
"InnoDB buffer pool <= 1G and Innodb_buffer_pool_instances(!=1)." ;
2015-08-19 12:45:24 +00:00
push ( @ adjvars , "innodb_buffer_pool_instances (=1)" ) ;
}
else {
goodprint "InnoDB buffer pool instances: "
. $ myvar { 'innodb_buffer_pool_instances' } . "" ;
}
}
}
2016-08-30 12:38:16 +00:00
# InnoDB Used Buffer Pool Size vs CHUNK size
2016-08-31 08:30:20 +00:00
if ( ! defined ( $ myvar { 'innodb_buffer_pool_chunk_size' } ) ) {
infoprint
"InnoDB Buffer Pool Chunk Size not used or defined in your version" ;
}
else {
2022-06-15 12:43:18 +00:00
infoprint "Number of InnoDB Buffer Pool Chunk: "
2016-08-31 08:30:20 +00:00
. int ( $ myvar { 'innodb_buffer_pool_size' } ) /
int ( $ myvar { 'innodb_buffer_pool_chunk_size' } ) . " for "
. $ myvar { 'innodb_buffer_pool_instances' }
. " Buffer Pool Instance(s)" ;
if (
int ( $ myvar { 'innodb_buffer_pool_size' } ) % (
int ( $ myvar { 'innodb_buffer_pool_chunk_size' } ) *
int ( $ myvar { 'innodb_buffer_pool_instances' } )
) eq 0
)
{
goodprint
2016-10-18 12:25:02 +00:00
"Innodb_buffer_pool_size aligned with Innodb_buffer_pool_chunk_size & Innodb_buffer_pool_instances" ;
2016-08-31 08:30:20 +00:00
}
else {
badprint
2016-10-18 12:25:02 +00:00
"Innodb_buffer_pool_size aligned with Innodb_buffer_pool_chunk_size & Innodb_buffer_pool_instances" ;
2016-08-31 08:30:20 +00:00
#push( @adjvars, "Adjust innodb_buffer_pool_instances, innodb_buffer_pool_chunk_size with innodb_buffer_pool_size" );
push ( @ adjvars ,
"innodb_buffer_pool_size must always be equal to or a multiple of innodb_buffer_pool_chunk_size * innodb_buffer_pool_instances"
) ;
}
2016-08-30 15:03:21 +00:00
}
2016-08-31 08:30:20 +00:00
2018-02-18 04:44:13 +00:00
# InnoDB Read efficiency
2015-08-19 12:45:24 +00:00
if ( defined $ mycalc { 'pct_read_efficiency' }
&& $ mycalc { 'pct_read_efficiency' } < 90 )
{
badprint "InnoDB Read buffer efficiency: "
. $ mycalc { 'pct_read_efficiency' } . "% ("
. ( $ mystat { 'Innodb_buffer_pool_read_requests' } -
$ mystat { 'Innodb_buffer_pool_reads' } )
2022-10-05 08:16:42 +00:00
. " hits / "
2015-08-19 12:45:24 +00:00
. $ mystat { 'Innodb_buffer_pool_read_requests' }
. " total)" ;
}
else {
goodprint "InnoDB Read buffer efficiency: "
. $ mycalc { 'pct_read_efficiency' } . "% ("
. ( $ mystat { 'Innodb_buffer_pool_read_requests' } -
$ mystat { 'Innodb_buffer_pool_reads' } )
2022-10-05 08:16:42 +00:00
. " hits / "
2015-08-19 12:45:24 +00:00
. $ mystat { 'Innodb_buffer_pool_read_requests' }
. " total)" ;
}
# InnoDB Write efficiency
if ( defined $ mycalc { 'pct_write_efficiency' }
&& $ mycalc { 'pct_write_efficiency' } < 90 )
{
2016-02-24 19:20:48 +00:00
badprint "InnoDB Write Log efficiency: "
2016-04-19 14:19:31 +00:00
. abs ( $ mycalc { 'pct_write_efficiency' } ) . "% ("
2016-04-14 21:11:18 +00:00
. abs ( $ mystat { 'Innodb_log_write_requests' } -
2016-02-24 19:20:48 +00:00
$ mystat { 'Innodb_log_writes' } )
2022-10-05 08:16:42 +00:00
. " hits / "
2016-02-24 19:20:48 +00:00
. $ mystat { 'Innodb_log_write_requests' }
2015-08-19 12:45:24 +00:00
. " total)" ;
}
else {
2023-02-27 16:49:36 +00:00
goodprint "InnoDB Write Log efficiency: "
2015-08-19 12:45:24 +00:00
. $ mycalc { 'pct_write_efficiency' } . "% ("
2016-02-24 19:20:48 +00:00
. ( $ mystat { 'Innodb_log_write_requests' } -
$ mystat { 'Innodb_log_writes' } )
2022-10-05 08:16:42 +00:00
. " hits / "
2016-02-24 19:20:48 +00:00
. $ mystat { 'Innodb_log_write_requests' }
2015-08-19 12:45:24 +00:00
. " total)" ;
}
# InnoDB Log Waits
2022-02-07 22:40:35 +00:00
$ mystat { 'Innodb_log_waits_computed' } = 0 ;
2022-02-07 22:34:34 +00:00
if ( defined ( $ mystat { 'Innodb_log_waits' } )
2023-06-07 17:29:41 +00:00
and defined ( $ mystat { 'Innodb_log_writes' } )
and $ mystat { 'Innodb_log_writes' } > 0.000001 )
2022-02-07 22:34:34 +00:00
{
$ mystat { 'Innodb_log_waits_computed' } =
$ mystat { 'Innodb_log_waits' } / $ mystat { 'Innodb_log_writes' } ;
}
else {
undef $ mystat { 'Innodb_log_waits_computed' } ;
}
if ( defined $ mystat { 'Innodb_log_waits_computed' }
&& $ mystat { 'Innodb_log_waits_computed' } > 0.000001 )
2015-08-19 12:45:24 +00:00
{
badprint "InnoDB log waits: "
. percentage ( $ mystat { 'Innodb_log_waits' } ,
$ mystat { 'Innodb_log_writes' } )
. "% ("
. $ mystat { 'Innodb_log_waits' }
. " waits / "
. $ mystat { 'Innodb_log_writes' }
. " writes)" ;
push ( @ adjvars ,
2021-10-15 08:39:03 +00:00
"innodb_log_buffer_size (> "
2015-08-19 12:45:24 +00:00
. hr_bytes_rnd ( $ myvar { 'innodb_log_buffer_size' } )
. ")" ) ;
}
else {
goodprint "InnoDB log waits: "
. percentage ( $ mystat { 'Innodb_log_waits' } ,
$ mystat { 'Innodb_log_writes' } )
. "% ("
. $ mystat { 'Innodb_log_waits' }
. " waits / "
. $ mystat { 'Innodb_log_writes' }
. " writes)" ;
}
$ result { 'Calculations' } = { % mycalc } ;
2015-06-18 08:56:47 +00:00
}
2015-06-18 20:02:55 +00:00
2018-09-20 13:11:34 +00:00
sub check_metadata_perf {
subheaderprint "Analysis Performance Metrics" ;
2019-09-25 20:05:45 +00:00
if ( defined $ myvar { 'innodb_stats_on_metadata' } ) {
infoprint "innodb_stats_on_metadata: "
. $ myvar { 'innodb_stats_on_metadata' } ;
2019-05-15 08:52:51 +00:00
if ( $ myvar { 'innodb_stats_on_metadata' } eq 'ON' ) {
badprint "Stat are updated during querying INFORMATION_SCHEMA." ;
push @ adjvars , "SET innodb_stats_on_metadata = OFF" ;
#Disabling innodb_stats_on_metadata
select_one ( "SET GLOBAL innodb_stats_on_metadata = OFF;" ) ;
return 1 ;
}
2018-09-20 13:11:34 +00:00
}
goodprint "No stat updates during querying INFORMATION_SCHEMA." ;
2018-11-26 12:57:11 +00:00
return 0 ;
2018-09-20 13:11:34 +00:00
}
2018-11-26 12:57:11 +00:00
2015-12-10 10:52:39 +00:00
# Recommendations for Database metrics
2015-06-18 20:02:55 +00:00
sub mysql_databases {
2015-08-19 12:45:24 +00:00
return if ( $ opt { dbstat } == 0 ) ;
2016-04-11 10:01:01 +00:00
subheaderprint "Database Metrics" ;
2015-08-19 12:45:24 +00:00
unless ( mysql_version_ge ( 5 , 5 ) ) {
infoprint
2023-02-27 16:49:36 +00:00
"Database metrics from information schema are missing in this version. Skipping..." ;
2015-08-19 12:45:24 +00:00
return ;
}
2021-01-28 07:44:14 +00:00
@ dblist = select_array (
"SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME NOT IN ( 'mysql', 'performance_schema', 'information_schema', 'sys' );"
2017-07-05 09:51:33 +00:00
) ;
2015-08-19 12:45:24 +00:00
infoprint "There is " . scalar ( @ dblist ) . " Database(s)." ;
my @ totaldbinfo = split /\s/ ,
select_one (
2022-06-30 12:46:54 +00:00
"SELECT SUM(TABLE_ROWS), SUM(DATA_LENGTH), SUM(INDEX_LENGTH), SUM(DATA_LENGTH+INDEX_LENGTH), COUNT(TABLE_NAME), COUNT(DISTINCT(TABLE_COLLATION)), COUNT(DISTINCT(ENGINE)) FROM information_schema.TABLES WHERE TABLE_SCHEMA NOT IN ('mysql', 'performance_schema', 'information_schema', 'sys');"
2015-08-19 12:45:24 +00:00
) ;
2017-05-19 00:06:36 +00:00
infoprint "All User Databases:" ;
2016-03-22 15:36:04 +00:00
infoprint " +-- TABLE : "
2022-02-07 22:34:34 +00:00
. select_one (
2022-06-30 12:46:54 +00:00
"SELECT count(*) from information_schema.TABLES WHERE TABLE_TYPE ='BASE TABLE' AND TABLE_SCHEMA NOT IN ('mysql', 'performance_schema', 'information_schema', 'sys')"
2022-02-07 22:34:34 +00:00
) . "" ;
2022-02-04 21:29:04 +00:00
infoprint " +-- VIEW : "
2022-02-07 22:34:34 +00:00
. select_one (
2022-06-30 12:46:54 +00:00
"SELECT count(*) from information_schema.TABLES WHERE TABLE_TYPE ='VIEW' AND TABLE_SCHEMA NOT IN ('mysql', 'performance_schema', 'information_schema', 'sys')"
2022-02-07 22:34:34 +00:00
) . "" ;
2022-02-04 21:29:04 +00:00
infoprint " +-- INDEX : "
2022-02-07 22:34:34 +00:00
. select_one (
2022-06-30 12:46:54 +00:00
"SELECT count(distinct(concat(TABLE_NAME, TABLE_SCHEMA, INDEX_NAME))) from information_schema.STATISTICS WHERE TABLE_SCHEMA NOT IN ('mysql', 'performance_schema', 'information_schema', 'sys')"
2022-02-07 22:34:34 +00:00
) . "" ;
2022-02-04 21:29:04 +00:00
infoprint " +-- CHARS : "
. ( $ totaldbinfo [ 5 ] eq 'NULL' ? 0 : $ totaldbinfo [ 5 ] ) . " ("
. (
join ", " ,
select_array (
2022-06-30 12:46:54 +00:00
"select distinct(CHARACTER_SET_NAME) from information_schema.columns WHERE CHARACTER_SET_NAME IS NOT NULL AND TABLE_SCHEMA NOT IN ('mysql', 'performance_schema', 'information_schema', 'sys');"
2022-02-07 22:34:34 +00:00
)
2022-02-04 21:29:04 +00:00
) . ")" ;
infoprint " +-- COLLA : "
. ( $ totaldbinfo [ 5 ] eq 'NULL' ? 0 : $ totaldbinfo [ 5 ] ) . " ("
. (
join ", " ,
select_array (
2022-06-30 12:46:54 +00:00
"SELECT DISTINCT(TABLE_COLLATION) FROM information_schema.TABLES WHERE TABLE_COLLATION IS NOT NULL AND TABLE_SCHEMA NOT IN ('mysql', 'performance_schema', 'information_schema', 'sys');"
2022-02-07 22:34:34 +00:00
)
2022-02-04 21:29:04 +00:00
) . ")" ;
2016-03-22 15:36:04 +00:00
infoprint " +-- ROWS : "
2015-08-19 12:45:24 +00:00
. ( $ totaldbinfo [ 0 ] eq 'NULL' ? 0 : $ totaldbinfo [ 0 ] ) . "" ;
2016-03-22 15:36:04 +00:00
infoprint " +-- DATA : "
2015-08-19 12:45:24 +00:00
. hr_bytes ( $ totaldbinfo [ 1 ] ) . "("
. percentage ( $ totaldbinfo [ 1 ] , $ totaldbinfo [ 3 ] ) . "%)" ;
2016-03-22 15:36:04 +00:00
infoprint " +-- INDEX : "
2015-08-19 12:45:24 +00:00
. hr_bytes ( $ totaldbinfo [ 2 ] ) . "("
. percentage ( $ totaldbinfo [ 2 ] , $ totaldbinfo [ 3 ] ) . "%)" ;
2016-03-22 15:36:04 +00:00
infoprint " +-- SIZE : " . hr_bytes ( $ totaldbinfo [ 3 ] ) . "" ;
2022-02-04 21:29:04 +00:00
infoprint " +-- ENGINE: "
2016-03-29 12:22:45 +00:00
. ( $ totaldbinfo [ 6 ] eq 'NULL' ? 0 : $ totaldbinfo [ 6 ] ) . " ("
. (
join ", " ,
2022-02-07 22:34:34 +00:00
select_array (
2022-06-30 12:46:54 +00:00
"SELECT DISTINCT(ENGINE) FROM information_schema.TABLES WHERE ENGINE IS NOT NULL AND TABLE_SCHEMA NOT IN ('mysql', 'performance_schema', 'information_schema', 'sys');"
2022-02-07 22:34:34 +00:00
)
2016-03-29 12:22:45 +00:00
) . ")" ;
2015-08-19 12:45:24 +00:00
$ result { 'Databases' } { 'All databases' } { 'Rows' } =
( $ totaldbinfo [ 0 ] eq 'NULL' ? 0 : $ totaldbinfo [ 0 ] ) ;
$ result { 'Databases' } { 'All databases' } { 'Data Size' } = $ totaldbinfo [ 1 ] ;
$ result { 'Databases' } { 'All databases' } { 'Data Pct' } =
percentage ( $ totaldbinfo [ 1 ] , $ totaldbinfo [ 3 ] ) . "%" ;
$ result { 'Databases' } { 'All databases' } { 'Index Size' } = $ totaldbinfo [ 2 ] ;
$ result { 'Databases' } { 'All databases' } { 'Index Pct' } =
percentage ( $ totaldbinfo [ 2 ] , $ totaldbinfo [ 3 ] ) . "%" ;
2016-03-29 12:22:45 +00:00
$ result { 'Databases' } { 'All databases' } { 'Total Size' } = $ totaldbinfo [ 3 ] ;
print "\n" unless ( $ opt { 'silent' } or $ opt { 'json' } ) ;
2023-09-26 20:32:07 +00:00
my $ nbViews = 0 ;
my $ nbTables = 0 ;
2015-08-19 12:45:24 +00:00
foreach ( @ dblist ) {
my @ dbinfo = split /\s/ ,
select_one (
2022-06-30 12:46:54 +00:00
"SELECT TABLE_SCHEMA, SUM(TABLE_ROWS), SUM(DATA_LENGTH), SUM(INDEX_LENGTH), SUM(DATA_LENGTH+INDEX_LENGTH), COUNT(DISTINCT ENGINE), COUNT(TABLE_NAME), COUNT(DISTINCT(TABLE_COLLATION)), COUNT(DISTINCT(ENGINE)) FROM information_schema.TABLES WHERE TABLE_SCHEMA='$_' GROUP BY TABLE_SCHEMA ORDER BY TABLE_SCHEMA"
2015-08-19 12:45:24 +00:00
) ;
next unless defined $ dbinfo [ 0 ] ;
2023-09-26 20:32:07 +00:00
infoprint "Database: " . $ dbinfo [ 0 ] . "" ;
$ nbTables = select_one (
2022-02-07 22:34:34 +00:00
"SELECT count(*) from information_schema.TABLES WHERE TABLE_TYPE ='BASE TABLE' AND TABLE_SCHEMA='$_'"
2023-09-26 20:32:07 +00:00
) ;
infoprint " +-- TABLE : $nbTables" ;
2022-02-04 21:29:04 +00:00
infoprint " +-- VIEW : "
2022-02-07 22:34:34 +00:00
. select_one (
"SELECT count(*) from information_schema.TABLES WHERE TABLE_TYPE ='VIEW' AND TABLE_SCHEMA='$_'"
) . "" ;
2022-02-04 21:29:04 +00:00
infoprint " +-- INDEX : "
2022-02-07 22:34:34 +00:00
. select_one (
"SELECT count(distinct(concat(TABLE_NAME, TABLE_SCHEMA, INDEX_NAME))) from information_schema.STATISTICS WHERE TABLE_SCHEMA='$_'"
) . "" ;
infoprint " +-- CHARS : "
. ( $ totaldbinfo [ 5 ] eq 'NULL' ? 0 : $ totaldbinfo [ 5 ] ) . " ("
. (
join ", " ,
select_array (
"select distinct(CHARACTER_SET_NAME) from information_schema.columns WHERE CHARACTER_SET_NAME IS NOT NULL AND TABLE_SCHEMA='$_';"
)
) . ")" ;
infoprint " +-- COLLA : "
2016-03-29 12:22:45 +00:00
. ( $ dbinfo [ 7 ] eq 'NULL' ? 0 : $ dbinfo [ 7 ] ) . " ("
. (
join ", " ,
select_array (
2022-02-04 21:29:04 +00:00
"SELECT DISTINCT(TABLE_COLLATION) FROM information_schema.TABLES WHERE TABLE_SCHEMA='$_' AND TABLE_COLLATION IS NOT NULL;"
2016-03-29 12:22:45 +00:00
)
) . ")" ;
2022-02-04 21:29:04 +00:00
infoprint " +-- ROWS : "
2015-08-19 12:45:24 +00:00
. ( ! defined ( $ dbinfo [ 1 ] ) or $ dbinfo [ 1 ] eq 'NULL' ? 0 : $ dbinfo [ 1 ] )
. "" ;
2022-02-04 21:29:04 +00:00
infoprint " +-- DATA : "
2015-08-19 12:45:24 +00:00
. hr_bytes ( $ dbinfo [ 2 ] ) . "("
. percentage ( $ dbinfo [ 2 ] , $ dbinfo [ 4 ] ) . "%)" ;
2022-02-04 21:29:04 +00:00
infoprint " +-- INDEX : "
2015-08-19 12:45:24 +00:00
. hr_bytes ( $ dbinfo [ 3 ] ) . "("
. percentage ( $ dbinfo [ 3 ] , $ dbinfo [ 4 ] ) . "%)" ;
2022-02-04 21:29:04 +00:00
infoprint " +-- TOTAL : " . hr_bytes ( $ dbinfo [ 4 ] ) . "" ;
infoprint " +-- ENGINE: "
2016-03-29 12:22:45 +00:00
. ( $ dbinfo [ 8 ] eq 'NULL' ? 0 : $ dbinfo [ 8 ] ) . " ("
. (
join ", " ,
select_array (
2022-02-04 21:29:04 +00:00
"SELECT DISTINCT(ENGINE) FROM information_schema.TABLES WHERE TABLE_SCHEMA='$_' AND ENGINE IS NOT NULL"
2016-03-29 12:22:45 +00:00
)
) . ")" ;
2022-02-04 15:01:22 +00:00
foreach my $ eng (
select_array (
2022-02-04 21:29:04 +00:00
"SELECT DISTINCT(ENGINE) FROM information_schema.TABLES WHERE TABLE_SCHEMA='$_' AND ENGINE IS NOT NULL"
2022-02-04 15:01:22 +00:00
)
)
{
infoprint " +-- ENGINE $eng : "
. select_one (
"SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA='$dbinfo[0]' AND ENGINE='$eng'"
) . " TABLE(s)" ;
}
2023-09-26 20:32:07 +00:00
if ( $ nbTables == 0 ) {
badprint " No table in $dbinfo[0] database" ;
next ;
}
2015-08-19 12:45:24 +00:00
badprint "Index size is larger than data size for $dbinfo[0] \n"
2017-02-07 05:56:17 +00:00
if ( $ dbinfo [ 2 ] ne 'NULL' )
and ( $ dbinfo [ 3 ] ne 'NULL' )
and ( $ dbinfo [ 2 ] < $ dbinfo [ 3 ] ) ;
2023-09-26 20:32:07 +00:00
if ( $ dbinfo [ 5 ] > 1 and $ nbTables > 0 ) {
2022-02-04 15:01:22 +00:00
badprint "There are "
. $ dbinfo [ 5 ]
. " storage engines. Be careful. \n" ;
push @ generalrec ,
"Select one storage engine (InnoDB is a good choice) for all tables in $dbinfo[0] database ($dbinfo[5] engines detected)" ;
2023-09-26 20:32:07 +00:00
}
2016-03-29 12:22:45 +00:00
$ result { 'Databases' } { $ dbinfo [ 0 ] } { 'Rows' } = $ dbinfo [ 1 ] ;
$ result { 'Databases' } { $ dbinfo [ 0 ] } { 'Tables' } = $ dbinfo [ 6 ] ;
$ result { 'Databases' } { $ dbinfo [ 0 ] } { 'Collations' } = $ dbinfo [ 7 ] ;
$ result { 'Databases' } { $ dbinfo [ 0 ] } { 'Data Size' } = $ dbinfo [ 2 ] ;
2015-08-19 12:45:24 +00:00
$ result { 'Databases' } { $ dbinfo [ 0 ] } { 'Data Pct' } =
percentage ( $ dbinfo [ 2 ] , $ dbinfo [ 4 ] ) . "%" ;
$ result { 'Databases' } { $ dbinfo [ 0 ] } { 'Index Size' } = $ dbinfo [ 3 ] ;
$ result { 'Databases' } { $ dbinfo [ 0 ] } { 'Index Pct' } =
percentage ( $ dbinfo [ 3 ] , $ dbinfo [ 4 ] ) . "%" ;
$ result { 'Databases' } { $ dbinfo [ 0 ] } { 'Total Size' } = $ dbinfo [ 4 ] ;
2016-03-22 16:56:08 +00:00
2016-03-29 12:22:45 +00:00
if ( $ dbinfo [ 7 ] > 1 ) {
badprint $ dbinfo [ 7 ]
2016-04-22 15:22:00 +00:00
. " different collations for database "
2016-03-29 12:22:45 +00:00
. $ dbinfo [ 0 ] ;
push ( @ generalrec ,
"Check all table collations are identical for all tables in "
. $ dbinfo [ 0 ]
. " database." ) ;
}
else {
goodprint $ dbinfo [ 7 ]
. " collation for "
. $ dbinfo [ 0 ]
. " database." ;
}
if ( $ dbinfo [ 8 ] > 1 ) {
badprint $ dbinfo [ 8 ]
2016-04-22 15:22:00 +00:00
. " different engines for database "
2016-03-29 12:22:45 +00:00
. $ dbinfo [ 0 ] ;
push ( @ generalrec ,
"Check all table engines are identical for all tables in "
. $ dbinfo [ 0 ]
. " database." ) ;
}
else {
goodprint $ dbinfo [ 8 ] . " engine for " . $ dbinfo [ 0 ] . " database." ;
}
my @ distinct_column_charset = select_array (
2022-02-03 19:00:37 +00:00
"select DISTINCT(CHARACTER_SET_NAME) from information_schema.COLUMNS where CHARACTER_SET_NAME IS NOT NULL AND TABLE_SCHEMA ='$_' AND CHARACTER_SET_NAME IS NOT NULL"
2016-03-29 12:22:45 +00:00
) ;
infoprint "Charsets for $dbinfo[0] database table column: "
. join ( ', ' , @ distinct_column_charset ) ;
if ( scalar ( @ distinct_column_charset ) > 1 ) {
badprint $ dbinfo [ 0 ]
2016-10-24 09:25:07 +00:00
. " table column(s) has several charsets defined for all text like column(s)." ;
2016-03-29 12:22:45 +00:00
push ( @ generalrec ,
"Limit charset for column to one charset if possible for "
. $ dbinfo [ 0 ]
. " database." ) ;
}
else {
goodprint $ dbinfo [ 0 ]
. " table column(s) has same charset defined for all text like column(s)." ;
}
my @ distinct_column_collation = select_array (
2022-02-03 19:00:37 +00:00
"select DISTINCT(COLLATION_NAME) from information_schema.COLUMNS where COLLATION_NAME IS NOT NULL AND TABLE_SCHEMA ='$_' AND COLLATION_NAME IS NOT NULL"
2016-03-29 12:22:45 +00:00
) ;
infoprint "Collations for $dbinfo[0] database table column: "
. join ( ', ' , @ distinct_column_collation ) ;
if ( scalar ( @ distinct_column_collation ) > 1 ) {
badprint $ dbinfo [ 0 ]
2016-10-24 09:25:07 +00:00
. " table column(s) has several collations defined for all text like column(s)." ;
2016-03-29 12:22:45 +00:00
push ( @ generalrec ,
"Limit collations for column to one collation if possible for "
. $ dbinfo [ 0 ]
. " database." ) ;
}
else {
goodprint $ dbinfo [ 0 ]
. " table column(s) has same collation defined for all text like column(s)." ;
}
2016-03-22 16:56:08 +00:00
}
2015-06-18 20:02:55 +00:00
}
2017-05-19 00:06:36 +00:00
# Recommendations for database columns
sub mysql_tables {
2018-09-20 12:51:07 +00:00
return if ( $ opt { tbstat } == 0 ) ;
2017-05-19 00:06:36 +00:00
subheaderprint "Table Column Metrics" ;
unless ( mysql_version_ge ( 5 , 5 ) ) {
infoprint
2023-02-27 16:49:36 +00:00
"Table column metrics from information schema are missing in this version. Skipping..." ;
2017-05-19 00:06:36 +00:00
return ;
}
2021-02-05 14:25:09 +00:00
if ( mysql_version_ge ( 8 ) and not mysql_version_eq ( 10 ) ) {
infoprint
2022-06-30 12:46:54 +00:00
"MySQL and Percona version 8.0 and greater have removed PROCEDURE ANALYSE feature" ;
2022-01-03 17:54:54 +00:00
$ opt { colstat } = 0 ;
infoprint "Disabling colstat parameter" ;
2019-10-01 22:07:46 +00:00
}
2023-03-11 06:48:00 +00:00
2023-04-25 22:14:12 +00:00
infoprint ( "Dumpdir: $opt{dumpdir}" ) ;
2023-06-07 17:29:41 +00:00
2023-03-11 06:46:01 +00:00
# Store all information schema in dumpdir if defined
if ( defined $ opt { dumpdir } and - d "$opt{dumpdir}" ) {
2023-03-11 06:48:00 +00:00
for my $ info_s_table (
select_array ( 'use information_schema;show tables;' ) )
{
infoprint "Dumping $info_s_table into $opt{dumpdir}" ;
select_csv_file (
"$opt{dumpdir}/ifs_${info_s_table}.csv" ,
"select * from information_schema.$info_s_table"
) ;
2023-03-11 06:46:01 +00:00
}
2023-06-07 17:29:41 +00:00
2023-06-07 16:22:02 +00:00
#exit 0 if ( $opt{stop} == 1 );
2023-03-11 06:46:01 +00:00
}
2022-02-04 15:01:22 +00:00
foreach ( select_user_dbs ( ) ) {
2017-07-05 09:51:33 +00:00
my $ dbname = $ _ ;
2017-05-19 00:06:36 +00:00
next unless defined $ _ ;
infoprint "Database: " . $ _ . "" ;
my @ dbtable = select_array (
"SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA='$dbname' AND TABLE_TYPE='BASE TABLE' ORDER BY TABLE_NAME"
2017-07-05 09:51:33 +00:00
) ;
foreach ( @ dbtable ) {
my $ tbname = $ _ ;
2017-05-19 00:06:36 +00:00
infoprint " +-- TABLE: $tbname" ;
2022-02-04 15:01:22 +00:00
infoprint " +-- TYPE: "
. select_one (
"SELECT ENGINE FROM information_schema.tables where TABLE_schema='$dbname' AND TABLE_NAME='$tbname'"
) ;
2022-01-03 17:54:54 +00:00
my $ selIdxReq = << "ENDSQL" ;
SELECT index_name AS idxname ,
GROUP_CONCAT ( column_name ORDER BY seq_in_index ) AS cols ,
INDEX_TYPE as type
FROM information_schema . statistics
WHERE INDEX_SCHEMA = '$dbname'
AND TABLE_NAME = '$tbname'
2022-01-31 13:36:28 +00:00
GROUP BY idxname , type
2022-01-03 17:54:54 +00:00
ENDSQL
2022-02-04 15:01:22 +00:00
my @ tbidx = select_array ( $ selIdxReq ) ;
my $ found = 0 ;
foreach my $ idx ( @ tbidx ) {
my @ info = split /\s/ , $ idx ;
next if $ info [ 0 ] eq 'NULL' ;
infoprint
" +-- Index $info[0] - Cols: $info[1] - Type: $info[2]" ;
$ found + + ;
2022-01-03 17:54:54 +00:00
}
2022-02-04 15:01:22 +00:00
if ( $ found == 0 ) {
badprint ( "Table $dbname.$tbname has no index defined" ) ;
push @ generalrec ,
"Add at least a primary key on table $dbname.$tbname" ;
2022-01-03 17:54:54 +00:00
}
2017-07-05 09:51:33 +00:00
my @ tbcol = select_array (
"SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='$dbname' AND TABLE_NAME='$tbname'"
) ;
foreach ( @ tbcol ) {
my $ ctype = select_one (
"SELECT COLUMN_TYPE FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='$dbname' AND TABLE_NAME='$tbname' AND COLUMN_NAME='$_' "
) ;
my $ isnull = select_one (
"SELECT IS_NULLABLE FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='$dbname' AND TABLE_NAME='$tbname' AND COLUMN_NAME='$_' "
) ;
2019-10-01 22:07:46 +00:00
2017-07-05 09:51:33 +00:00
my $ current_type =
2022-01-30 14:38:54 +00:00
uc ( $ ctype ) . ( $ isnull eq 'NO' ? " NOT NULL" : " NULL" ) ;
2021-02-05 14:25:09 +00:00
my $ optimal_type = '' ;
2022-01-03 17:54:54 +00:00
infoprint " +-- Column $tbname.$_: $current_type" ;
2021-07-02 16:31:21 +00:00
if ( $ opt { colstat } == 1 ) {
$ optimal_type = select_str_g ( "Optimal_fieldtype" ,
2021-03-30 09:54:30 +00:00
"SELECT \\`$_\\` FROM \\`$dbname\\`.\\`$tbname\\` PROCEDURE ANALYSE(100000)"
2021-07-02 16:31:21 +00:00
)
unless ( mysql_version_ge ( 8 )
and not mysql_version_eq ( 10 ) ) ;
2021-03-30 09:54:30 +00:00
}
2019-10-01 22:07:46 +00:00
if ( $ optimal_type eq '' ) {
2022-02-04 15:01:22 +00:00
2022-01-03 17:54:54 +00:00
#infoprint " +-- Current Fieldtype: $current_type";
2021-02-05 14:25:09 +00:00
2019-10-01 22:07:46 +00:00
#infoprint " Optimal Fieldtype: Not available";
2018-04-26 12:15:59 +00:00
}
2021-02-05 14:25:09 +00:00
elsif ( $ current_type ne $ optimal_type
and $ current_type !~ /.*DATETIME.*/
and $ current_type !~ /.*TIMESTAMP.*/ )
{
2022-01-03 17:54:54 +00:00
infoprint " +-- Current Fieldtype: $current_type" ;
2021-02-05 14:25:09 +00:00
if ( $ optimal_type =~ /.*ENUM\(.*/ ) {
$ optimal_type = "ENUM( ... )" ;
2019-10-01 22:44:54 +00:00
}
2022-01-03 17:54:54 +00:00
infoprint " +-- Optimal Fieldtype: $optimal_type " ;
2021-02-05 14:25:09 +00:00
if ( $ optimal_type !~ /.*ENUM\(.*/ ) {
2019-10-01 22:44:54 +00:00
badprint
2017-07-05 09:51:33 +00:00
"Consider changing type for column $_ in table $dbname.$tbname" ;
2021-02-05 14:25:09 +00:00
push ( @ generalrec ,
2019-09-25 20:05:45 +00:00
"ALTER TABLE \`$dbname\`.\`$tbname\` MODIFY \`$_\` $optimal_type;"
2021-02-05 14:25:09 +00:00
) ;
}
2017-07-05 09:51:33 +00:00
}
else {
goodprint "$dbname.$tbname ($_) type: $current_type" ;
}
2017-05-19 00:06:36 +00:00
}
2017-07-05 09:51:33 +00:00
}
2017-05-19 00:06:36 +00:00
}
}
2015-12-10 10:52:39 +00:00
# Recommendations for Indexes metrics
2015-07-01 22:19:28 +00:00
sub mysql_indexes {
2015-08-19 12:45:24 +00:00
return if ( $ opt { idxstat } == 0 ) ;
2016-04-11 10:01:01 +00:00
subheaderprint "Indexes Metrics" ;
2015-08-19 12:45:24 +00:00
unless ( mysql_version_ge ( 5 , 5 ) ) {
infoprint
2023-02-27 16:49:36 +00:00
"Index metrics from information schema are missing in this version. Skipping..." ;
2015-08-19 12:45:24 +00:00
return ;
}
2016-03-29 12:22:45 +00:00
2016-03-14 11:10:35 +00:00
# unless ( mysql_version_ge( 5, 6 ) ) {
# infoprint
2016-04-22 15:22:00 +00:00
#"Skip Index metrics from information schema due to erroneous information provided in this version";
2016-03-14 11:10:35 +00:00
# return;
# }
2015-08-19 12:45:24 +00:00
my $ selIdxReq = << 'ENDSQL' ;
2015-07-02 10:16:02 +00:00
SELECT
2022-06-30 12:46:54 +00:00
CONCAT ( t . TABLE_SCHEMA , '.' , t . TABLE_NAME ) AS 'table' ,
CONCAT ( s . INDEX_NAME , '(' , s . COLUMN_NAME , ')' ) AS 'index'
2015-07-02 10:16:02 +00:00
, s . SEQ_IN_INDEX AS 'seq'
, s2 . max_columns AS 'maxcol'
, s . CARDINALITY AS 'card'
, t . TABLE_ROWS AS 'est_rows'
2016-10-24 09:21:56 +00:00
, INDEX_TYPE as type
2015-07-02 10:16:02 +00:00
, ROUND ( ( ( s . CARDINALITY / IFNULL ( t . TABLE_ROWS , 0.01 ) ) * 100 ) , 2 ) AS 'sel'
FROM INFORMATION_SCHEMA . STATISTICS s
INNER JOIN INFORMATION_SCHEMA . TABLES t
ON s . TABLE_SCHEMA = t . TABLE_SCHEMA
AND s . TABLE_NAME = t . TABLE_NAME
INNER JOIN (
2015-11-23 07:08:25 +00:00
SELECT
2015-07-02 10:16:02 +00:00
TABLE_SCHEMA
, TABLE_NAME
, INDEX_NAME
, MAX ( SEQ_IN_INDEX ) AS max_columns
FROM INFORMATION_SCHEMA . STATISTICS
WHERE TABLE_SCHEMA NOT IN ( 'mysql' , 'information_schema' , 'performance_schema' )
2016-03-22 08:54:26 +00:00
AND INDEX_TYPE < > 'FULLTEXT'
2015-07-02 10:16:02 +00:00
GROUP BY TABLE_SCHEMA , TABLE_NAME , INDEX_NAME
) AS s2
ON s . TABLE_SCHEMA = s2 . TABLE_SCHEMA
AND s . TABLE_NAME = s2 . TABLE_NAME
AND s . INDEX_NAME = s2 . INDEX_NAME
WHERE t . TABLE_SCHEMA NOT IN ( 'mysql' , 'information_schema' , 'performance_schema' )
AND t . TABLE_ROWS > 10
AND s . CARDINALITY IS NOT NULL
AND ( s . CARDINALITY / IFNULL ( t . TABLE_ROWS , 0.01 ) ) < 8.00
ORDER BY sel
LIMIT 10 ;
ENDSQL
2015-08-19 12:45:24 +00:00
my @ idxinfo = select_array ( $ selIdxReq ) ;
infoprint "Worst selectivity indexes:" ;
foreach ( @ idxinfo ) {
debugprint "$_" ;
my @ info = split /\s/ ;
infoprint "Index: " . $ info [ 1 ] . "" ;
2017-01-26 21:00:00 +00:00
infoprint " +-- COLUMN : " . $ info [ 0 ] . "" ;
2015-08-19 12:45:24 +00:00
infoprint " +-- NB SEQS : " . $ info [ 2 ] . " sequence(s)" ;
infoprint " +-- NB COLS : " . $ info [ 3 ] . " column(s)" ;
infoprint " +-- CARDINALITY : " . $ info [ 4 ] . " distinct values" ;
infoprint " +-- NB ROWS : " . $ info [ 5 ] . " rows" ;
2016-03-29 12:22:45 +00:00
infoprint " +-- TYPE : " . $ info [ 6 ] ;
2016-03-22 08:54:26 +00:00
infoprint " +-- SELECTIVITY : " . $ info [ 7 ] . "%" ;
2015-08-19 12:45:24 +00:00
2017-07-05 09:51:33 +00:00
$ result { 'Indexes' } { $ info [ 1 ] } { 'Column' } = $ info [ 0 ] ;
$ result { 'Indexes' } { $ info [ 1 ] } { 'Sequence number' } = $ info [ 2 ] ;
$ result { 'Indexes' } { $ info [ 1 ] } { 'Number of column' } = $ info [ 3 ] ;
$ result { 'Indexes' } { $ info [ 1 ] } { 'Cardinality' } = $ info [ 4 ] ;
$ result { 'Indexes' } { $ info [ 1 ] } { 'Row number' } = $ info [ 5 ] ;
$ result { 'Indexes' } { $ info [ 1 ] } { 'Index Type' } = $ info [ 6 ] ;
$ result { 'Indexes' } { $ info [ 1 ] } { 'Selectivity' } = $ info [ 7 ] ;
2016-03-22 08:54:26 +00:00
if ( $ info [ 7 ] < 25 ) {
2015-08-19 12:45:24 +00:00
badprint "$info[1] has a low selectivity" ;
}
2016-03-29 12:22:45 +00:00
}
2022-01-03 17:54:54 +00:00
infoprint "Indexes per database:" ;
2022-02-04 15:01:22 +00:00
foreach my $ dbname ( select_user_dbs ( ) ) {
infoprint "Database: " . $ dbname . "" ;
$ selIdxReq = << "ENDSQL" ;
2022-06-30 12:46:54 +00:00
SELECT concat ( table_name , '.' , index_name ) AS idxname ,
2022-02-04 16:49:49 +00:00
GROUP_CONCAT ( column_name ORDER BY seq_in_index ) AS cols ,
SUM ( CARDINALITY ) as card ,
INDEX_TYPE as type
FROM information_schema . statistics
WHERE INDEX_SCHEMA = '$dbname'
AND index_name IS NOT NULL
GROUP BY table_name , idxname , type
2022-01-03 17:54:54 +00:00
ENDSQL
2022-02-04 15:01:22 +00:00
my $ found = 0 ;
foreach my $ idxinfo ( select_array ( $ selIdxReq ) ) {
my @ info = split /\s/ , $ idxinfo ;
next if $ info [ 0 ] eq 'NULL' ;
infoprint " +-- INDEX : " . $ info [ 0 ] ;
infoprint " +-- COLUMNS : " . $ info [ 1 ] ;
infoprint " +-- CARDINALITY: " . $ info [ 2 ] ;
infoprint " +-- TYPE : " . $ info [ 4 ] if defined $ info [ 4 ] ;
infoprint " +-- COMMENT : " . $ info [ 5 ] if defined $ info [ 5 ] ;
$ found + + ;
}
2023-09-26 20:42:36 +00:00
my $ nbTables = select_one (
"SELECT count(*) from information_schema.TABLES WHERE TABLE_TYPE ='BASE TABLE' AND TABLE_SCHEMA='$dbname'"
) ;
badprint "No index found for $dbname database" if $ found == 0 and $ nbTables > 1 ;
2022-02-04 15:01:22 +00:00
push @ generalrec , "Add indexes on tables from $dbname database"
2023-09-26 20:42:36 +00:00
if $ found == 0 and $ nbTables > 1 ;
2022-01-03 17:54:54 +00:00
}
2015-08-19 12:45:24 +00:00
return
unless ( defined ( $ myvar { 'performance_schema' } )
and $ myvar { 'performance_schema' } eq 'ON' ) ;
$ selIdxReq = << 'ENDSQL' ;
2022-06-30 12:46:54 +00:00
SELECT CONCAT ( object_schema , '.' , object_name ) AS 'table' , index_name
2015-07-02 14:42:53 +00:00
FROM performance_schema . table_io_waits_summary_by_index_usage
WHERE index_name IS NOT NULL
2023-02-27 16:49:36 +00:00
AND count_star = 0
2015-11-23 07:08:25 +00:00
AND index_name < > 'PRIMARY'
2022-06-30 12:46:54 +00:00
AND object_schema NOT IN ( 'mysql' , 'performance_schema' , 'information_schema' )
2015-07-02 14:42:53 +00:00
ORDER BY count_star , object_schema , object_name ;
ENDSQL
2015-08-19 12:45:24 +00:00
@ idxinfo = select_array ( $ selIdxReq ) ;
2015-12-10 10:52:39 +00:00
infoprint "Unused indexes:" ;
2015-08-19 12:45:24 +00:00
push ( @ generalrec , "Remove unused indexes." ) if ( scalar ( @ idxinfo ) > 0 ) ;
foreach ( @ idxinfo ) {
debugprint "$_" ;
my @ info = split /\s/ ;
badprint "Index: $info[1] on $info[0] is not used." ;
push @ { $ result { 'Indexes' } { 'Unused Indexes' } } ,
$ info [ 0 ] . "." . $ info [ 1 ] ;
}
2015-07-01 22:19:28 +00:00
}
2015-08-19 12:45:24 +00:00
2023-06-07 16:22:02 +00:00
sub mysql_views {
2022-01-03 17:54:54 +00:00
subheaderprint "Views Metrics" ;
unless ( mysql_version_ge ( 5 , 5 ) ) {
infoprint
2023-02-27 16:49:36 +00:00
"Views metrics from information schema are missing in this version. Skipping..." ;
2022-01-03 17:54:54 +00:00
return ;
}
}
2023-06-07 16:22:02 +00:00
sub mysql_routines {
2022-01-03 17:54:54 +00:00
subheaderprint "Routines Metrics" ;
unless ( mysql_version_ge ( 5 , 5 ) ) {
infoprint
2023-02-27 16:49:36 +00:00
"Routines metrics from information schema are missing in this version. Skipping..." ;
2022-01-03 17:54:54 +00:00
return ;
}
}
2023-06-07 16:22:02 +00:00
sub mysql_triggers {
2022-01-03 17:54:54 +00:00
subheaderprint "Triggers Metrics" ;
unless ( mysql_version_ge ( 5 , 5 ) ) {
infoprint
2023-02-27 16:49:36 +00:00
"Trigger metrics from information schema are missing in this version. Skipping..." ;
2022-01-03 17:54:54 +00:00
return ;
}
}
2022-02-04 15:01:22 +00:00
2008-09-08 01:16:39 +00:00
# Take the two recommendation arrays and display them at the end of the output
sub make_recommendations {
2022-06-23 12:31:46 +00:00
$ result { 'Recommendations' } = \ @ generalrec ;
2022-02-12 22:33:59 +00:00
$ result { 'AdjustVariables' } = \ @ adjvars ;
2016-04-11 10:01:01 +00:00
subheaderprint "Recommendations" ;
2015-08-19 12:45:24 +00:00
if ( @ generalrec > 0 ) {
prettyprint "General recommendations:" ;
foreach ( @ generalrec ) { prettyprint " " . $ _ . "" ; }
}
if ( @ adjvars > 0 ) {
prettyprint "Variables to adjust:" ;
if ( $ mycalc { 'pct_max_physical_memory' } > 90 ) {
prettyprint
" *** MySQL's maximum memory usage is dangerously high ***\n"
. " *** Add RAM before increasing MySQL buffer variables ***" ;
}
foreach ( @ adjvars ) { prettyprint " " . $ _ . "" ; }
}
if ( @ generalrec == 0 && @ adjvars == 0 ) {
2016-03-29 12:22:45 +00:00
prettyprint "No additional performance recommendations are available." ;
2015-08-19 12:45:24 +00:00
}
2008-09-08 01:16:39 +00:00
}
2015-08-19 12:45:24 +00:00
2015-08-26 13:23:19 +00:00
sub close_outputfile {
2015-08-19 12:45:24 +00:00
close ( $ fh ) if defined ( $ fh ) ;
2015-06-17 16:03:44 +00:00
}
2015-07-16 15:14:42 +00:00
sub headerprint {
2022-06-23 12:31:46 +00:00
prettyprint " >> MySQLTuner $tunerversion\n"
2022-02-13 16:15:44 +00:00
. "\t * Jean-Marie Renouard <jmrenouard\@gmail.com>\n"
2022-02-12 22:33:59 +00:00
. "\t * Major Hayden <major\@mhtx.net>\n"
2020-09-03 16:17:58 +00:00
. " >> Bug reports, feature requests, and downloads at http://mysqltuner.pl/\n"
2015-08-19 12:45:24 +00:00
. " >> Run with '--help' for additional options and output filtering" ;
2015-07-16 15:14:42 +00:00
}
2015-08-26 13:23:19 +00:00
sub string2file {
2016-03-29 12:22:45 +00:00
my $ filename = shift ;
my $ content = shift ;
open my $ fh , q( > ) , $ filename
or die
"Unable to open $filename in write mode. Please check permissions for this file or directory" ;
print $ fh $ content if defined ( $ content ) ;
close $ fh ;
debugprint $ content if ( $ opt { 'debug' } ) ;
2015-08-26 13:23:19 +00:00
}
sub file2array {
my $ filename = shift ;
2016-03-29 12:22:45 +00:00
debugprint "* reading $filename" if ( $ opt { 'debug' } ) ;
2015-08-26 13:23:19 +00:00
my $ fh ;
open ( $ fh , q( < ) , "$filename" )
or die "Couldn't open $filename for reading: $!\n" ;
my @ lines = <$fh> ;
close ( $ fh ) ;
return @ lines ;
}
sub file2string {
2016-03-29 12:22:45 +00:00
return join ( '' , file2array ( @ _ ) ) ;
2015-08-26 13:23:19 +00:00
}
my $ templateModel ;
2016-03-29 12:22:45 +00:00
if ( $ opt { 'template' } ne 0 ) {
$ templateModel = file2string ( $ opt { 'template' } ) ;
}
else {
# DEFAULT REPORT TEMPLATE
$ templateModel = << 'END_TEMPLATE' ;
2015-08-26 13:23:19 +00:00
< ! DOCTYPE html >
<html>
<head>
2015-12-10 10:52:39 +00:00
<title> MySQLTuner Report </title>
2015-08-26 13:23:19 +00:00
< meta charset = "UTF-8" >
</head>
<body>
<h1> Result output </h1>
<pre>
{ $ data }
</pre>
</body>
</html>
END_TEMPLATE
}
2016-03-29 12:22:45 +00:00
2015-07-16 15:14:42 +00:00
sub dump_result {
2021-10-15 11:56:27 +00:00
2021-10-15 11:43:07 +00:00
#debugprint Dumper( \%result ) if ( $opt{'debug'} );
2015-08-26 13:23:19 +00:00
debugprint "HTML REPORT: $opt{'reportfile'}" ;
2015-11-23 07:14:28 +00:00
2016-03-29 12:22:45 +00:00
if ( $ opt { 'reportfile' } ne 0 ) {
2016-08-31 08:30:20 +00:00
eval { require Text::Template } ;
2018-11-30 13:06:49 +00:00
eval { require JSON } ;
2016-03-29 12:22:45 +00:00
if ( $@ ) {
badprint "Text::Template Module is needed." ;
2018-09-23 18:19:06 +00:00
die "Text::Template Module is needed." ;
2016-03-29 12:22:45 +00:00
}
2019-09-25 20:05:45 +00:00
my $ json = JSON - > new - > allow_nonref ;
my $ json_text = $ json - > pretty - > encode ( \ % result ) ;
my % vars = (
'data' = > \ % result ,
2018-11-30 13:06:49 +00:00
'debug' = > $ json_text ,
) ;
2016-03-29 12:22:45 +00:00
my $ template ;
{
no warnings 'once' ;
$ template = Text::Template - > new (
2019-09-25 20:05:45 +00:00
TYPE = > 'STRING' ,
PREPEND = > q{ ; } ,
SOURCE = > $ templateModel ,
2018-11-30 13:06:49 +00:00
DELIMITERS = > [ '[%' , '%]' ]
2016-03-29 12:22:45 +00:00
) or die "Couldn't construct template: $Text::Template::ERROR" ;
}
2018-09-23 18:19:06 +00:00
2016-03-29 12:22:45 +00:00
open my $ fh , q( > ) , $ opt { 'reportfile' }
or die
2018-11-26 12:57:11 +00:00
"Unable to open $opt{'reportfile'} in write mode. please check permissions for this file or directory" ;
2018-11-30 13:06:49 +00:00
$ template - > fill_in ( HASH = > \ % vars , OUTPUT = > $ fh ) ;
2016-03-29 12:22:45 +00:00
close $ fh ;
}
2018-09-23 18:19:06 +00:00
2016-03-29 12:22:45 +00:00
if ( $ opt { 'json' } ne 0 ) {
2016-08-31 08:30:20 +00:00
eval { require JSON } ;
2018-11-26 12:57:11 +00:00
if ( $@ ) {
2016-08-30 13:37:42 +00:00
print "$bad JSON Module is needed.\n" ;
2018-09-23 18:19:06 +00:00
return 1 ;
2016-03-29 12:22:45 +00:00
}
2018-09-23 18:19:06 +00:00
2016-03-29 12:22:45 +00:00
my $ json = JSON - > new - > allow_nonref ;
2018-11-26 12:57:11 +00:00
print $ json - > utf8 ( 1 ) - > pretty ( ( $ opt { 'prettyjson' } ? 1 : 0 ) )
- > encode ( \ % result ) ;
2018-09-23 18:19:06 +00:00
if ( $ opt { 'outputfile' } ne 0 ) {
2018-11-26 12:57:11 +00:00
unlink $ opt { 'outputfile' } if ( - e $ opt { 'outputfile' } ) ;
2018-09-23 18:19:06 +00:00
open my $ fh , q( > ) , $ opt { 'outputfile' }
or die
2018-11-26 12:57:11 +00:00
"Unable to open $opt{'outputfile'} in write mode. please check permissions for this file or directory" ;
print $ fh $ json - > utf8 ( 1 ) - > pretty ( ( $ opt { 'prettyjson' } ? 1 : 0 ) )
- > encode ( \ % result ) ;
close $ fh ;
2018-09-23 18:19:06 +00:00
}
2016-01-27 13:50:29 +00:00
}
2015-07-16 15:14:42 +00:00
}
2015-08-19 12:45:24 +00:00
2016-04-18 14:45:34 +00:00
sub which {
2016-04-19 14:19:31 +00:00
my $ prog_name = shift ;
2016-04-18 14:45:34 +00:00
my $ path_string = shift ;
2016-04-19 14:19:31 +00:00
my @ path_array = split /:/ , $ ENV { 'PATH' } ;
2016-04-18 14:45:34 +00:00
2016-04-19 14:19:31 +00:00
for my $ path ( @ path_array ) {
2018-09-23 18:19:06 +00:00
return "$path/$prog_name" if ( - x "$path/$prog_name" ) ;
2016-04-18 14:45:34 +00:00
}
2016-04-19 14:19:31 +00:00
return 0 ;
2016-04-18 14:45:34 +00:00
}
2008-09-08 01:16:39 +00:00
# ---------------------------------------------------------------------------
# BEGIN 'MAIN'
# ---------------------------------------------------------------------------
2017-07-05 09:51:33 +00:00
headerprint ; # Header Print
2017-05-19 00:06:36 +00:00
2022-09-13 13:17:39 +00:00
validate_tuner_version ; # Check latest version
2016-08-31 08:30:20 +00:00
mysql_setup ; # Gotta login first
2018-02-22 15:58:59 +00:00
debugprint "MySQL FINAL Client : $mysqlcmd $mysqllogin" ;
debugprint "MySQL Admin FINAL Client : $mysqladmincmd $mysqllogin" ;
2018-03-19 16:17:11 +00:00
2018-02-22 15:58:59 +00:00
#exit(0);
2021-02-05 14:25:09 +00:00
os_setup ; # Set up some OS variables
get_all_vars ; # Toss variables/status into hashes
2022-09-13 13:17:39 +00:00
get_tuning_info ; # Get information about the tuning connection
2023-06-07 15:23:33 +00:00
calculations ; # Calculate everything we need
2023-06-22 13:15:25 +00:00
check_architecture ; # Suggest 64-bit upgrade
check_storage_engines ; # Show enabled storage engines
2023-06-07 17:29:41 +00:00
if ( $ opt { 'feature' } ne '' ) {
subheaderprint "See FEATURES.md for more information" ;
no strict 'refs' ;
for my $ feature ( split /,/ , $ opt { 'feature' } ) {
subheaderprint "Running feature: $opt{'feature'}" ;
$ feature - > ( ) ;
}
2023-06-22 13:15:25 +00:00
make_recommendations ;
2023-06-07 16:22:02 +00:00
exit ( 0 ) ;
2023-06-07 15:23:33 +00:00
}
2021-02-05 14:25:09 +00:00
validate_mysql_version ; # Check current MySQL version
2016-08-31 08:30:20 +00:00
2022-09-13 13:17:39 +00:00
system_recommendations ; # Avoid too many services on the same host
2021-02-05 14:25:09 +00:00
log_file_recommendations ; # check log file content
2018-09-20 13:11:34 +00:00
2023-07-06 06:19:29 +00:00
check_metadata_perf ; # Show parameter impacting performance during analysis
mysql_databases ; # Show information about databases
mysql_tables ; # Show information about table column
mysql_table_structures ; # Show information about table structures
2022-06-23 12:31:46 +00:00
2023-07-06 06:19:29 +00:00
mysql_indexes ; # Show information about indexes
mysql_views ; # Show information about views
mysql_triggers ; # Show information about triggers
mysql_routines ; # Show information about routines
security_recommendations ; # Display some security recommendations
cve_recommendations ; # Display related CVE
2023-06-07 15:23:33 +00:00
2023-07-06 06:19:29 +00:00
mysql_stats ; # Print the server stats
mysql_pfs ; # Print Performance schema info
2023-02-28 12:51:46 +00:00
2023-07-06 06:19:29 +00:00
mariadb_threadpool ; # Print MariaDB ThreadPool stats
mysql_myisam ; # Print MyISAM stats
mysql_innodb ; # Print InnoDB stats
mariadb_aria ; # Print MariaDB Aria stats
mariadb_tokudb ; # Print MariaDB Tokudb stats
mariadb_xtradb ; # Print MariaDB XtraDB stats
2022-02-07 23:15:59 +00:00
#mariadb_rockdb; # Print MariaDB RockDB stats
#mariadb_spider; # Print MariaDB Spider stats
#mariadb_connect; # Print MariaDB Connect stats
2021-02-05 14:25:09 +00:00
mariadb_galera ; # Print MariaDB Galera Cluster stats
get_replication_status ; # Print replication info
make_recommendations ; # Make recommendations based on stats
dump_result ; # Dump result if debug is on
close_outputfile ; # Close reportfile if needed
2015-08-19 12:45:24 +00:00
2008-09-08 01:16:39 +00:00
# ---------------------------------------------------------------------------
# END 'MAIN'
# ---------------------------------------------------------------------------
2015-08-25 15:00:06 +00:00
1 ;
2015-08-26 13:23:19 +00:00
2015-07-01 10:31:40 +00:00
__END__
2017-06-15 17:53:20 +00:00
2015-07-01 10:31:40 +00:00
= pod
2015-07-01 11:33:57 +00:00
2015-07-01 10:31:40 +00:00
= encoding UTF - 8
= head1 NAME
2023-09-26 20:50:57 +00:00
MySQLTuner 2.3 .2 - MySQL High Performance Tuning Script
2015-07-01 10:31:40 +00:00
= head1 IMPORTANT USAGE GUIDELINES
To run the script with the default options , run the script without arguments
Allow MySQL server to run for at least 24 - 48 hours before trusting suggestions
Some routines may require root level privileges ( script will provide warnings )
You must provide the remote server ' s total memory when connecting to other servers
2018-02-18 04:41:14 +00:00
= head1 CONNECTION AND AUTHENTICATION
2015-07-01 10:31:40 +00:00
2017-06-15 18:57:07 +00:00
- - host <hostname> Connect to a remote host to perform tests ( default: localhost )
- - socket <socket> Use a different socket for a local connection
- - port <port> Port to use for connection ( default: 3306 )
2022-02-07 23:31:00 +00:00
- - protocol tcp Force TCP connection instead of socket
2017-06-15 18:57:07 +00:00
- - user <username> Username to use for authentication
- - userenv <envvar> Name of env variable which contains username to use for authentication
- - pass <password> Password to use for authentication
- - passenv <envvar> Name of env variable which contains password to use for authentication
2017-09-15 08:53:57 +00:00
- - ssl - ca <path> Path to public key
2017-06-15 18:57:07 +00:00
- - mysqladmin <path> Path to a custom mysqladmin executable
- - mysqlcmd <path> Path to a custom mysql executable
- - defaults - file <path> Path to a custom . my . cnf
2023-02-27 16:49:36 +00:00
- - defaults - extra - file <path> Path to an extra custom config file
2022-09-13 13:17:39 +00:00
- - server - log <path> Path to explicit log file ( error_log )
2017-06-15 17:53:20 +00:00
2015-07-01 10:31:40 +00:00
= head1 PERFORMANCE AND REPORTING OPTIONS
2016-03-24 22:58:48 +00:00
- - skipsize Don ' t enumerate tables and their types / sizes ( default: on )
( Recommended for servers with many tables )
2022-02-07 22:34:34 +00:00
- - json Print result as JSON string
- - prettyjson Print result as JSON formatted string
2022-06-30 12:46:54 +00:00
- - skippassword Don ' t perform checks on user passwords ( default: off )
2016-03-24 22:58:48 +00:00
- - checkversion Check for updates to MySQLTuner ( default: don ' t check )
- - updateversion Check for updates to MySQLTuner and update when newer version is available ( default: don ' t check )
- - forcemem <size> Amount of RAM installed in megabytes
- - forceswap <size> Amount of swap memory configured in megabytes
2022-09-13 13:17:39 +00:00
- - passwordfile <path> Path to a password file list ( one password by line )
2022-02-07 22:34:34 +00:00
- - cvefile <path> CVE File for vulnerability checks
- - outputfile <path> Path to a output txt file
- - reportfile <path> Path to a report txt file
- - template <path> Path to a template file
2023-02-28 13:34:14 +00:00
- - dumpdir <path> Path to a directory where to dump information files
2023-06-07 16:22:02 +00:00
- - feature <feature> Run a specific feature ( see FEATURES section )
2015-07-01 10:31:40 +00:00
= head1 OUTPUT OPTIONS
2016-01-05 23:57:34 +00:00
2016-03-24 22:58:48 +00:00
- - silent Don ' t output anything on screen
2022-09-13 13:17:39 +00:00
- - verbose Print out all options ( default: no verbose , dbstat , idxstat , sysstat , tbstat , pfstat )
2023-09-08 12:14:49 +00:00
- - color Print output in color
2022-02-07 22:34:34 +00:00
- - nocolor Don ' t print output in color
2016-03-24 22:58:48 +00:00
- - nogood Remove OK responses
- - nobad Remove negative / suggestion responses
- - noinfo Remove informational responses
- - debug Print debug information
2022-02-07 22:34:34 +00:00
- - noprocess Consider no other process is running
2016-03-24 22:58:48 +00:00
- - dbstat Print database information
2022-09-13 13:17:39 +00:00
- - nodbstat Don ' t print database information
2018-09-20 12:51:07 +00:00
- - tbstat Print table information
2022-09-13 13:17:39 +00:00
- - notbstat Don ' t print table information
2021-03-30 09:54:30 +00:00
- - colstat Print column information
2022-09-13 13:17:39 +00:00
- - nocolstat Don ' t print column information
2016-03-24 22:58:48 +00:00
- - idxstat Print index information
2022-09-13 13:17:39 +00:00
- - noidxstat Don ' t print index information
2023-07-06 05:46:45 +00:00
- - nomyisamstat Don ' t print MyIsam information
2016-03-30 15:16:16 +00:00
- - sysstat Print system information
2022-09-13 13:17:39 +00:00
- - nosysstat Don ' t print system information
2023-07-06 05:46:45 +00:00
- - nostructstat Don ' t print table structures information
2016-10-24 09:21:56 +00:00
- - pfstat Print Performance schema
2022-09-13 13:17:39 +00:00
- - nopfstat Don ' t print Performance schema
2022-06-30 12:46:54 +00:00
- - bannedports Ports banned separated by comma ( , )
- - server - log Define specific error_log to analyze
2022-09-13 13:17:39 +00:00
- - maxportallowed Number of open ports allowable on this host
2016-03-24 22:58:48 +00:00
- - buffers Print global and per - thread buffer values
2018-11-26 12:57:11 +00:00
2015-07-01 11:33:57 +00:00
= head1 PERLDOC
2015-07-01 10:31:40 +00:00
You can find documentation for this module with the perldoc command .
perldoc mysqltuner
2015-12-10 10:52:39 +00:00
= head2 INTERNALS
2015-08-19 16:25:25 +00:00
L <https://github.com/major/MySQLTuner-perl/blob/master/INTERNALS.md>
Internal documentation
2015-07-01 10:31:40 +00:00
= head1 AUTHORS
Major Hayden - major @ mhtx . net
2023-02-10 06:22:14 +00:00
Jean - Marie Renouard - jmrenouard @ gmail . com
2015-07-01 10:31:40 +00:00
= head1 CONTRIBUTORS
= over 4
= item *
Matthew Montgomery
= item *
Paul Kehrer
= item *
Dave Burgess
= item *
Jonathan Hinds
= item *
Mike Jackson
= item *
Nils Breunese
= item *
Shawn Ashlee
= item *
Luuk Vosslamber
= item *
Ville Skytta
= item *
Trent Hornibrook
= item *
Jason Gill
= item *
Mark Imbriaco
= item *
Greg Eden
= item *
Aubin Galinotti
= item *
Giovanni Bechis
= item *
Bill Bradford
= item *
Ryan Novosielski
= item *
Michael Scheidell
= item *
Blair Christensen
= item *
Hans du Plooy
= item *
Victor Trac
= item *
Everett Barnes
= item *
Tom Krouper
= item *
Gary Barrueto
= item *
Simon Greenaway
= item *
Adam Stein
= item *
Isart Montane
= item *
Baptiste M .
= item *
Cole Turner
= item *
Major Hayden
2015-07-15 09:09:51 +00:00
= item *
Joe Ashcraft
2015-07-16 15:14:42 +00:00
= item *
Jean - Marie Renouard
2015-12-10 10:52:39 +00:00
= item *
2016-01-05 23:57:34 +00:00
Stephan GroBberndt
2015-12-10 10:52:39 +00:00
2016-08-30 11:34:52 +00:00
= item *
Christian Loos
2023-02-28 12:51:46 +00:00
= item *
Long Radix
2015-07-01 10:31:40 +00:00
= back
= head1 SUPPORT
2015-07-01 11:39:16 +00:00
2020-09-03 16:17:58 +00:00
Bug reports , feature requests , and downloads at http: //m ysqltuner . pl /
2015-07-01 11:39:16 +00:00
2015-07-01 10:31:40 +00:00
Bug tracker can be found at https: //gi thub . com /major/ MySQLTuner - perl / issues
2015-07-01 11:39:16 +00:00
2023-02-10 06:22:14 +00:00
Maintained by Jean - Marie Renouard ( jmrenouard \ @ gmail . com ) - Licensed under GPL
2015-07-01 10:31:40 +00:00
= head1 SOURCE CODE
L <https://github.com/major/MySQLTuner-perl>
2015-07-01 11:39:16 +00:00
git clone https: //gi thub . com /major/ MySQLTuner - perl . git
2015-07-01 10:31:40 +00:00
= head1 COPYRIGHT AND LICENSE
2023-02-10 06:22:14 +00:00
Copyright ( C ) 2006 - 2023 Major Hayden - major @ mhtx . net
# Copyright (C) 2015-2023 Jean-Marie Renouard - jmrenouard@gmail.com
2015-07-01 10:31:40 +00:00
2020-09-03 16:17:58 +00:00
For the latest updates , please visit http: //m ysqltuner . pl /
2015-07-01 11:39:16 +00:00
2019-03-22 06:32:47 +00:00
Git repository available at https: //gi thub . com /major/ MySQLTuner - perl
2015-07-01 10:31:40 +00:00
This program is free software: you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
2015-07-01 11:39:16 +00:00
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
See the GNU General Public License for more details .
2015-07-01 10:31:40 +00:00
You should have received a copy of the GNU General Public License
2019-03-22 06:32:47 +00:00
along with this program . If not , see <https://www.gnu.org/licenses/> .
2015-07-01 10:31:40 +00:00
= cut
2011-03-08 18:37:58 +00:00
# Local variables:
# indent-tabs-mode: t
# cperl-indent-level: 8
# perl-indent-level: 8
2020-09-03 16:17:58 +00:00
# End: