A lot of new info about indexes and table structures

This commit is contained in:
Jean-Marie Renouard 2022-01-03 18:54:54 +01:00
parent c1661f326e
commit 926c9a92ca

View file

@ -1,5 +1,5 @@
#!/usr/bin/env perl
# mysqltuner.pl - Version 1.8.5
# mysqltuner.pl - Version 1.8.7
# High Performance MySQL Tuning Script
# Copyright (C) 2006-2021 Major Hayden - major@mhtx.net
#
@ -56,7 +56,7 @@ use Cwd 'abs_path';
#use Env;
# Set up a few variables for use in the script
my $tunerversion = "1.8.5";
my $tunerversion = "1.8.7";
my ( @adjvars, @generalrec );
# Set defaults
@ -1064,6 +1064,51 @@ sub select_str_g {
return trim(@val);
}
sub select_user_dbs {
return select_array("SELECT DISTINCT TABLE_SCHEMA FROM information_schema.TABLES WHERE TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'percona', 'sys')")
}
sub select_tables_db()
{
my $schema=shift;
return select_array("SELECT DISTINCT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA='$schema'")
}
sub select_indexes_db()
{
my $schema=shift;
return select_array("SELECT DISTINCT INDEX_NAME FROM information_schema.STATISTICS WHERE TABLE_SCHEMA='$schema'")
}
sub select_views_db
{
my $schema=shift;
return select_array("SELECT DISTINCT TABLE_NAME FROM information_schema.VIEWS WHERE TABLE_SCHEMA='$schema'")
}
sub select_triggers_db
{
my $schema=shift;
return select_array("SELECT DISTINCT TRIGGER_NAME FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA='$schema'")
}
sub select_routines_db
{
my $schema=shift;
return select_array("SELECT DISTINCT ROUTINE_NAME FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA='$schema'")
}
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'")
}
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'")
}
sub get_tuning_info {
my @infoconn = select_array "\\s";
my ( $tkey, $tval );
@ -3521,7 +3566,7 @@ sub mysql_myisam {
. hr_bytes( $myvar{'key_buffer_size'} )
. " cache)";
#push(@adjvars,"key_buffer_size (\~ ".hr_num( $myvar{'key_buffer_size'} * $mycalc{'pct_key_buffer_used'} / 100).")");
push(@adjvars,"key_buffer_size (\~ ".hr_num( $myvar{'key_buffer_size'} * $mycalc{'pct_key_buffer_used'} / 100).")");
}
else {
goodprint "Key buffer used: $mycalc{'pct_key_buffer_used'}% ("
@ -6120,12 +6165,21 @@ sub mysql_databases {
"SELECT DISTINCT(ENGINE) FROM information_schema.TABLES WHERE TABLE_SCHEMA='$_'"
)
) . ")";
foreach my $eng(select_array(
"SELECT DISTINCT(ENGINE) FROM information_schema.TABLES WHERE TABLE_SCHEMA='$_'"
)) {
infoprint " +-- ENGINE $eng : " .
select_one("SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA='$dbinfo[0]' AND ENGINE='$eng'") .
" TABLE(s)";
}
badprint "Index size is larger than data size for $dbinfo[0] \n"
if ( $dbinfo[2] ne 'NULL' )
and ( $dbinfo[3] ne 'NULL' )
and ( $dbinfo[2] < $dbinfo[3] );
badprint "There are " . $dbinfo[5] . " storage engines. Be careful. \n"
if $dbinfo[5] > 1;
unless ($dbinfo[5] == 1) {
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)";
}
$result{'Databases'}{ $dbinfo[0] }{'Rows'} = $dbinfo[1];
$result{'Databases'}{ $dbinfo[0] }{'Tables'} = $dbinfo[6];
$result{'Databases'}{ $dbinfo[0] }{'Collations'} = $dbinfo[7];
@ -6217,8 +6271,11 @@ sub mysql_tables {
if ( mysql_version_ge(8) and not mysql_version_eq(10) ) {
infoprint
"MySQL and Percona version 8 and greater have remove PROCEDURE ANALYSE feature";
$opt{colstat} = 0;
infoprint "Disabling colstat parameter";
}
foreach (@dblist) {
foreach (select_user_dbs()) {
my $dbname = $_;
next unless defined $_;
infoprint "Database: " . $_ . "";
@ -6228,6 +6285,28 @@ sub mysql_tables {
foreach (@dbtable) {
my $tbname = $_;
infoprint " +-- TABLE: $tbname";
infoprint " +-- TYPE: ".select_one("SELECT ENGINE FROM information_schema.tables where TABLE_schema='$dbname' AND TABLE_NAME='$tbname'");
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'
ENDSQL
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++;
}
if ($found == 0) {
badprint ("Table $dbname.$tbname has no index defined");
push @generalrec, "Add at least a primary key on table $dbname.$tbname";
}
my @tbcol = select_array(
"SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='$dbname' AND TABLE_NAME='$tbname'"
);
@ -6239,11 +6318,10 @@ sub mysql_tables {
"SELECT IS_NULLABLE FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='$dbname' AND TABLE_NAME='$tbname' AND COLUMN_NAME='$_' "
);
infoprint " +-- Column $tbname.$_:";
my $current_type =
uc($ctype) . ( $isnull eq 'NO' ? " NOT NULL" : "" );
uc($ctype) . ( $isnull eq 'NO' ? " NOT NULL" : "NULL" );
my $optimal_type = '';
infoprint " +-- Column $tbname.$_: $current_type";
if ( $opt{colstat} == 1 ) {
$optimal_type = select_str_g( "Optimal_fieldtype",
"SELECT \\`$_\\` FROM \\`$dbname\\`.\\`$tbname\\` PROCEDURE ANALYSE(100000)"
@ -6252,7 +6330,7 @@ sub mysql_tables {
and not mysql_version_eq(10) );
}
if ( $optimal_type eq '' ) {
infoprint " Current Fieldtype: $current_type";
#infoprint " +-- Current Fieldtype: $current_type";
#infoprint " Optimal Fieldtype: Not available";
}
@ -6260,11 +6338,11 @@ sub mysql_tables {
and $current_type !~ /.*DATETIME.*/
and $current_type !~ /.*TIMESTAMP.*/ )
{
infoprint " Current Fieldtype: $current_type";
infoprint " +-- Current Fieldtype: $current_type";
if ( $optimal_type =~ /.*ENUM\(.*/ ) {
$optimal_type = "ENUM( ... )";
}
infoprint " Optimal Fieldtype: $optimal_type ";
infoprint " +-- Optimal Fieldtype: $optimal_type ";
if ( $optimal_type !~ /.*ENUM\(.*/ ) {
badprint
"Consider changing type for column $_ in table $dbname.$tbname";
@ -6360,7 +6438,34 @@ ENDSQL
badprint "$info[1] has a low selectivity";
}
}
infoprint "Indexes per database:";
foreach my $dbname (select_user_dbs()) {
infoprint "Database: " . $dbname . "";
$selIdxReq = <<"ENDSQL";
SELECT concat(concat(table_name,'.'), index_name) AS idxname,
GROUP_CONCAT(column_name ORDER BY seq_in_index) AS cols,
CARDINALITY as card,
INDEX_TYPE as type,
COMMENT as comment
FROM information_schema.statistics
WHERE INDEX_SCHEMA='$dbname'
AND index_name IS NOT NULL
ENDSQL
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++;
}
badprint "No index found for $dbname database" if $found == 0;
push @generalrec, "Add indexes on tables from $dbname database" if $found == 0;
}
return
unless ( defined( $myvar{'performance_schema'} )
and $myvar{'performance_schema'} eq 'ON' );
@ -6386,6 +6491,38 @@ ENDSQL
}
}
sub mysql_views()
{
subheaderprint "Views Metrics";
unless ( mysql_version_ge( 5, 5 ) ) {
infoprint
"Skip Index metrics from information schema missing in this version";
return;
}
}
sub mysql_routines()
{
subheaderprint "Routines Metrics";
unless ( mysql_version_ge( 5, 5 ) ) {
infoprint
"Skip Index metrics from information schema missing in this version";
return;
}
}
sub mysql_triggers()
{
subheaderprint "Triggers Metrics";
unless ( mysql_version_ge( 5, 5 ) ) {
infoprint
"Skip Index metrics from information schema missing in this version";
return;
}
}
# Take the two recommendation arrays and display them at the end of the output
sub make_recommendations {
$result{'Recommendations'} = \@generalrec;
@ -6569,6 +6706,9 @@ mysql_databases; # Show informations about databases
mysql_tables; # Show informations about table column
mysql_indexes; # Show informations about indexes
mysql_views; # Show informations about views
mysql_triggers; # Show informations about triggers
mysql_routines; # Show informations about routines
security_recommendations; # Display some security recommendations
cve_recommendations; # Display related CVE
calculations; # Calculate everything we need
@ -6603,7 +6743,7 @@ __END__
=head1 NAME
MySQLTuner 1.8.5 - MySQL High Performance Tuning Script
MySQLTuner 1.8.7 - MySQL High Performance Tuning Script
=head1 IMPORTANT USAGE GUIDELINES