Documentation Home
MySQL 5.6 リファレンスマニュアル
Download this Manual
PDF (US Ltr) - 27.1Mb
PDF (A4) - 27.1Mb
EPUB - 7.5Mb
HTML Download (TGZ) - 7.2Mb
HTML Download (Zip) - 7.2Mb


13.7.2.2 CHECK TABLE 構文

CHECK TABLE tbl_name [, tbl_name] ... [option] ...

option = {FOR UPGRADE | QUICK | FAST | MEDIUM | EXTENDED | CHANGED}

CHECK TABLE は、1 つまたは複数のテーブルをエラーがないかどうかチェックします。CHECK TABLE は、InnoDBMyISAMARCHIVE、および CSV テーブルに対して機能します。MyISAM テーブルの場合は、キー統計の更新も実行されます。

テーブルをチェックするには、それに対する何らかの権限が必要です。

CHECK TABLE はまた、ビューをチェックして、そのビュー定義で参照されているテーブルが存在しなくなっているなどの問題がないかどうかを調べることもできます。

CHECK TABLE はパーティション化されたテーブルに対してサポートされているため、ALTER TABLE ... CHECK PARTITION を使用して 1 つ以上のパーティションをチェックできます。詳細は、セクション13.1.7「ALTER TABLE 構文」およびセクション19.3.4「パーティションの保守」を参照してください。

MySQL 5.6.11 でのみ、このステートメントを発行する前に、gtid_nextAUTOMATIC に設定する必要があります。(Bug #16062608、Bug #16715809、Bug #69045)

出力

CHECK TABLE は、次のカラムを含む結果セットを返します。

カラム
Table テーブル名
Op 常に check
Msg_type statuserrorinfonote、または warning
Msg_text 情報メッセージ

このステートメントによって、チェックされたテーブルごとに多数の情報行が生成される可能性があります。最後の行には statusMsg_type 値が含まれ、Msg_text は通常 OK になります。OK または Table is already up to date が得られない場合は通常、そのテーブルの修復を実行するべきです。セクション7.6「MyISAM テーブルの保守とクラッシュリカバリ」を参照してください。Table is already up to date は、そのテーブルのストレージエンジンがテーブルのチェックは必要ないと判断したことを示します。

バージョン互換性のチェック

FOR UPGRADE オプションは、指定されたテーブルが現在のバージョンの MySQL と互換性があるかどうかをチェックします。FOR UPGRADE を指定すると、サーバーは各テーブルをチェックして、テーブルの作成後にそのテーブルのいずれかのデータ型またはインデックスで互換性のない変更が発生しているかどうかを判定します。発生していない場合は、チェックが成功します。それ以外で、非互換性の可能性がある場合、サーバーはそのテーブルに対して完全なチェックを実行します (これには、ある程度時間がかかることがあります)。完全なチェックが成功した場合、サーバーは、そのテーブルの .frm ファイルを現在の MySQL バージョン番号でマークします。.frm ファイルをマークすると、このテーブルに対する同じバージョンのサーバーによるそれ以降のチェックが確実に速くなります。

データ型のストレージフォーマットが変更されたか、またはそのソート順序が変更されたために非互換性が発生する可能性があります。弊社の目的はそれらの変更を避けることですが、各リリースの間の非適合性よりもさらに深刻な問題を修正するために必要である場合もあります。

現在、FOR UPGRADE では、次の非互換性が検出されています。

  • InnoDB および MyISAM テーブルの TEXT カラム内の最後の領域のインデックス順序が MySQL 4.1 と 5.0 の間で変更されました。

  • 新しい DECIMAL データ型のストレージ方法が MySQL 5.0.3 と 5.0.5 の間で変更されました。

  • テーブルが、現在実行しているものとは異なるバージョンの MySQL サーバーによって作成された場合、FOR UPGRADE は、そのテーブルに互換性のないバージョンの .frm ファイルが含まれていることを示します。この場合、CHECK TABLE によって返される結果セットには、Msg_type 値が error で、Msg_text 値が Table upgrade required. Please do "REPAIR TABLE `tbl_name`" to fix it! である行が含まれています。

  • 文字セットまたは照合順序に対して、テーブルインデックスの再構築が必要な変更が加えられる場合があります。これらの変更や、それが FOR UPGRADE によっていつ検出されるかの詳細は、セクション2.11.3「テーブルまたはインデックスの再構築が必要かどうかのチェック」を参照してください。

  • YEAR(2) データ型は、MySQL 5.6.6 の時点では非推奨です。YEAR(2) カラムを含むテーブルの場合、CHECK TABLE では、YEAR(2)YEAR(4) に変換する REPAIR TABLE が推奨されます。

データ一貫性のチェック

指定できるその他のチェックオプションを次の表に示します。これらのオプションはストレージエンジンに渡されますが、そこで使用される場合とされない場合があります。

意味
QUICK 正しくないリンクをチェックするための行のスキャンを行いません。InnoDB および MyISAM テーブルとビューに適用されます。
FAST 正しく閉じられていないテーブルのみを検査します。MyISAM テーブルとビューにのみ適用されます。InnoDB では無視されます。
CHANGED 最後のチェック以降に変更されたか、または正しく閉じられていないテーブルのみをチェックします。MyISAM テーブルとビューにのみ適用されます。InnoDB では無視されます。
MEDIUM 削除されたリンクが有効であることを検証するために行をスキャンします。また、行のキーチェックサムも計算し、キーの計算されたチェックサムを使用してこれを検証します。MyISAM テーブルとビューにのみ適用されます。InnoDB では無視されます。
EXTENDED 行ごとにすべてのキーの完全なキールックアップを実行します。これにより、テーブルの 100% の整合性が保証されますが、長い時間がかかります。MyISAM テーブルとビューにのみ適用されます。InnoDB では無視されます。

QUICKMEDIUM、または EXTENDED オプションのいずれも指定されていない場合、動的フォーマットの MyISAM テーブルに対するデフォルトのチェックタイプは MEDIUM です。これにより、そのテーブルに対して myisamchk --medium-check tbl_name を実行したのと同じ結果が得られます。また、CHANGED または FAST が指定されていないかぎり、静的フォーマットの MyISAM テーブルに対するデフォルトのチェックタイプも MEDIUM です。指定されている場合、デフォルトは QUICK です。CHANGED および FAST の場合、行はめったに破損しないため、行スキャンはスキップされます。

チェックオプションは、次の例のように組み合わせることができます。この例では、テーブルが正しく閉じられたかどうかを判定するために、そのテーブルに対してすばやいチェックを実行します。

CHECK TABLE test_table FAST QUICK;
注記

場合によっては、CHECK TABLE によってテーブルが変更されます。これは、テーブルが破損しているまたは正しく閉じられていないとしてマークされているが、CHECK TABLE でそのテーブル内に何も問題が見つからなかった場合に発生します。この場合、CHECK TABLE はそのテーブルを正常としてマークします。

テーブルが破損している場合、もっとも可能性が高いのはデータ部分ではなく、インデックス内の問題です。前のチェックタイプはすべて、インデックスを徹底的にチェックするため、ほとんどのエラーが見つかるはずです。

正常と見なしているテーブルをチェックするだけの場合は、チェックオプションを使用しないか、または QUICK オプションを使用するようにしてください。後者は、急いでおり、かつ QUICK でデータファイル内のエラーが見つからないという非常に小さなリスクを負える場合に使用するようにしてください。(ほとんどの場合、通常の使用状況では、MySQL でデータファイル内のどのようなエラーも見つかります。見つかった場合、そのテーブルは破損しているとしてマークされ、修復されるまで使用できなくなります。)

FAST および CHANGED は主に、テーブルをときどきチェックする場合にスクリプトから使用される (たとえば、cron から実行される) ことを目的にしています。ほとんどの場合、FASTCHANGED より優先されます。(優先されない唯一の場合は、MyISAM コード内にバグが見つかったのではないかと疑われるときです。)

EXTENDED は、通常のチェックを実行したが、MySQL が行を更新するか、またはキーで行を検索しようとすると引き続きテーブルで奇妙なエラーが発生する場合にのみ使用されます。通常のチェックが成功した場合、これはめったに発生しません。

CHECK TABLE ... EXTENDED を使用すると、クエリーオプティマイザによって生成される実行計画に影響を与える可能性があります。

CHECK TABLE によってレポートされる次のいくつかの問題は、自動的には修正できません。

  • Found row where the auto_increment column has the value 0

    これは、AUTO_INCREMENT インデックスカラムに値 0 が含まれている行がテーブル内に存在することを示します。(AUTO_INCREMENT カラムが 0 である行は、UPDATE ステートメントを使用してそのカラムを明示的に 0 に設定することによって作成できます。)

    これは、それ自体エラーではありませんが、そのテーブルをダンプしてリストアするか、またはそのテーブルに対して ALTER TABLE を実行しようとした場合に問題が発生する可能性があります。この場合、AUTO_INCREMENT カラムはその AUTO_INCREMENT カラムのルールに従って値を変更するため、重複キーエラーなどの問題が発生する可能性があります。

    この警告を解消するには、単純に、そのカラムを 0 以外の何からの値に設定するために UPDATE ステートメントを実行します。

InnoDB テーブル

次の注意事項は、InnoDB テーブルに適用されます。

  • CHECK TABLEInnoDB テーブルの問題が見つかった場合、サーバーはエラーの伝播を回避するためにシャットダウンする可能性があります。このエラーの詳細はエラーログに書き込まれます。

  • CHECK TABLE は、InnoDB テーブルまたはインデックスに破損またはエラーを検出すると、エラーをレポートします。サーバーをシャットダウンすることはしません。MySQL 5.5 からは、そのインデックスまたはテーブルのそれ以上の使用を防ぐために、CHECK TABLE は通常、そのインデックスを破損しているとしてマークし、またそのテーブルも同様にマークする場合があります。

  • CHECK TABLE は、セカンダリインデックス内のエントリ数の間違いを見つけた場合、エラーをレポートしますが、サーバーをシャットダウンしたり、ファイルへのアクセスを防いだりはしません。

  • CHECK TABLE はインデックスページの構造を調査してから、各キーエントリを調査します。キーポインタをクラスタ化されたレコードに対して検証したり、BLOB ポインタのパスに従ったりはしません。

  • InnoDB テーブルが file-per-table モードで独自の .ibd ファイル に格納されると、.ibd の最初の 3 つのページには、テーブルまたはインデックスデータではなくヘッダー情報が含まれます。CHECK TABLE ステートメントは、ヘッダーデータにのみ影響を与える不整合を検出しません。InnoDB .ibd ファイルの内容全体を検証するには、innochecksum コマンドを使用します。

  • 大きな InnoDB テーブルに対して CHECK TABLE を実行すると、CHECK TABLE の実行中にほかのスレッドがブロックされる可能性があります。タイムアウトを回避するために、CHECK TABLE 操作の場合は、セマフォー待機のしきい値 (600 秒) が 2 時間 (7200 秒) 延長されます。InnoDB は、240 秒以上のセマフォー待機を検出すると、InnoDB モニターの出力をエラーログに出力し始めます。ロック要求がセマフォー待機のしきい値を超えて延長された場合、InnoDB はそのプロセスを中止します。セマフォー待機が完全にタイムアウトする可能性を回避するには、CHECK TABLE の代わりに CHECK TABLE QUICK を実行できます。


User Comments
  Posted by Zach Gorman on February 5, 2004
Here is a php function you can use in a cron php script to periodically check the database for errors.

I check with $fast = true every 5 minutes and $fast = false every day.

# CheckSqlTables()
# Checks all tables in a database. Returns true if
# everything went successfully; returns false and fills
# out $msg if it did not.
function CheckSqlTables(&$msg, $fast = true) {
$msg = "";
ConnectToDb(); // Connect to your database here.

$rs_tables = mysql_query("SHOW TABLES");
if (!$rs_tables || mysql_num_rows($rs_tables) <= 0) {
$msg = "Could not iterate database tables\n";
return false;
}

$bOk = true;
$checktype = "";
if ($fast)
$checktype = "FAST";
while (list($tname) = mysql_fetch_row($rs_tables)) {
$rs_status = mysql_query("CHECK TABLE `$tname` $checktype");
if (!$rs_status || mysql_num_rows($rs_status) <= 0) {
$msg .= "Could not get status for table $tname\n";
$bOk = false;
continue;
}
# Seek to last row
mysql_data_seek($rs_status, mysql_num_rows($rs_status)-1);
$row_status = mysql_fetch_assoc($rs_status);
if ($row_status['Msg_type'] != "status") {
$msg .= "Table {$row_status['Table']}: ";
$msg .= "{$row_status['Msg_type']} = {$row_status['Msg_text']}\n";
$bOk = false;
}
}
return $bOk;
}

  Posted by Greg Fenton on May 12, 2004
I've taken Zach Gorman's example and made it directly ready for use via cron. Tested with PHP 4.3.2 on FreeBSD 4.3.
----------------------------------------------
#!/usr/local/bin/php

<?php

/*
 * Script to check the validity of MYSQL tables by running CHECK TABLE
 * on every table in the given database.
 *
 * To use:
 *    php -f <path_to_script> [-- options]
 *
 * (need to use "--" to separate script options from PHP options
 *
 * Example:
 *    php -f /usr/local/bin/check_mysql_tables.php -- -verbose -fast
 *
 * An example cron entry, checks each day at 2:02am:
 *    2 2 * * * /bin/php -f /bin/check_mysql_tables.php
 *
 */
$usage "Checks the validity of tables in a mysql database\n\n" .
         
"Usage: " $argv[0] . " [options]\n" .
         
"  -f[ast]    perform a fast check (CHECK TABLE tblName FAST)\n" .
         
"  -<?|h|x>   show usage string (this message)\n" .
         
"  -v[erbose] display verbose messages while running\n";

$msg "";
$fast false;
$verbose false;
$server "localhost";
$database "test";
$uid "root";
$pwd "";
$tcount 0;

array_shift($argv);  // take out the script name

foreach ($argv as $option) {
    switch (
$option) {
    case 
'-f':
    case 
'-fast':
        
$fast true;
        break;
    case 
'-v':
    case 
'-verbose':
        
$verbose true;
        echo 
"Verbose enabled\n";
        break;
    case 
'-x':
    case 
'-?':
    case 
'-h':
        die(
$usage);
        break;
    default:
        die(
"Unknown parameter: " $option "\n\n" $usage);
        break;
    }
}

if ( ! 
mysql_connect($server$uid$pwd) ) {
       die(
"Failed connecting to server: " mysql_error());
}

if (
$verbose) echo "Connected to server: $server\n";

if ( ! 
mysql_select_db($database) ) {
       die( 
"Failed selecting database '$database': " mysql_error() );
}

if (
$verbose) echo "Selected database: " $database "\n";

$rs_tables mysql_query("SHOW TABLES");
if (!
$rs_tables || (($num_tables mysql_num_rows($rs_tables)) <= 0) ) {
       die( 
"Could not iterate database tables\n" );
}
if (
$verbose) echo "Number of tables: $num_tables\n";

$bOk true;
$checktype "";

if (
$fast$checktype "FAST";

while (list(
$tname) = mysql_fetch_row($rs_tables)) {
    
$query "CHECK TABLE `$tname$checktype";
    if (
$verboseprintf("%3d. $query:\n", ++$tcount);

    
$rs_status mysql_query$query );
    if (!
$rs_status || mysql_num_rows($rs_status) <= ) {
        
$msg .= "Could not get status for table $tname\n";
        
$bOk false;
        continue;
    }

    
// seek to last row
    
mysql_data_seek($rs_statusmysql_num_rows($rs_status)-1);
    
$row_status mysql_fetch_assoc($rs_status);
    if (
$row_status['Msg_type'] != "status") {
        
$msg .= "Table {$row_status['Table']}: ";
        
$msg .= "{$row_status['Msg_type']} = {$row_status['Msg_text']}\n";
        
$bOk false;
        if (
$verbose) echo "  ** Check failed!!\n";
    }
    if (
$verbose) {
        echo 
"       {$row_status['Msg_type']} -> {$row_status['Msg_text']}\n";
    }

}

if ( ! 
$bOk ) die( "Check failed: \n\n" $msg );

exit(
0);
?>

  Posted by Stu Bray on September 21, 2004
Here is a bash script insipired by the php code posted here by Greg Fenton and Zach Gorman. It works nicely with cron, and has been tested on both linux and darwin. Note that on darwin, the dbexclude feature will not work due to word boundary anchor bugs in regex.

#!/bin/bash
#
# This is a small bash script that checks all mysql databases for errors
# and mails a log file to a specified email address. All variables are
# hardcoded for ease of use with cron. Any databases you wish not to check
# should be added to the DBEXCLUDE list, with a space in between each name.
#
# Note that DBEXCLUDE will only work with GNU sed, as BSD regular expressions
# on Darwin seem to have some trouble with word boundary anchors.
#
# sbray@csc.uvic.ca, UVic Fine Arts 2004.
# Some of this code was inspired from automysqlbackup.sh.2.0
# http://sourceforge.net/projects/automysqlbackup/

# system variables (change these according to your system)
USER=username
PASSWORD=password
DBHOST=localhost
LOGFILE=./mysql_check.log
MAILTO=root@localhost
TYPE1= # extra params to CHECK_TABLE e.g. FAST
TYPE2=
CORRUPT=no # start by assuming no corruption
DBNAMES="all" # or a list delimited by space
DBEXCLUDE="" # or a list delimited by space

# I/O redirection...
touch $LOGFILE
exec 6>&1
exec > $LOGFILE # stdout redirected to $LOGFILE

echo -n "Logfile: "
date
echo "---------------------------------------------------------"
echo

# Get our list of databases to check...
# NOTE: the DBEXCLUDE feature seemed to only work with Linux regex, GNU sed
if test $DBNAMES = "all" ; then
DBNAMES="`mysql --user=$USER --password=$PASSWORD --batch -N -e "show databases"`"
for i in $DBEXCLUDE
do
DBNAMES=`echo $DBNAMES | sed "s/\b$i\b//g"`
done
fi

# Run through each database and execute our CHECK TABLE command for each table...
for i in $DBNAMES
do
# to fancy up our log file
echo ""
echo "Database: $i"
echo "---------------------------------------------------------"

DBTABLES="`mysql --user=$USER --password=$PASSWORD $i --batch -N -e "show tables"`"

for j in $DBTABLES
do
echo "CHECK TABLE $j $TYPE1 $TYPE2" | mysql -u$USER -p$PASSWORD $i
done
echo ""
done

exec 1>&6 6>&- # Restore stdout and close file descriptor #6

# test our logfile for corruption in the database...
for i in `cat $LOGFILE`
do
if test $i = "warning" ; then
CORRUPT=yes
elif test $i = "error" ; then
CORRUPT=yes
fi
done

# send off our results...
if test $CORRUPT = "yes" ; then
cat $LOGFILE | mail -s "MySQL CHECK Log [ERROR FOUND] for $DBHOST-`date`" $MAILTO
else
cat $LOGFILE | mail -s "MySQL CHECK Log [PASSED OK] for $HOST-`date`" $MAILTO
fi
  Posted by Eric Barnes on November 16, 2004
For anyone who refuses to give up their VB6 (like me), here's a code snippet for you. You need to make sure you have the Microsoft Active X Data Objects Library referenced in your project.

Private Sub dbCheck()
Dim chkConn, chkRs

Set chkConn = New ADODB.Connection
Set chkRs = New ADODB.Recordset

chkConn.CursorLocation = adUseClient
chkConn.ConnectionString = "DRIVER={MySQL ODBC 3.51 Driver};uid=maximus;password=allhail;server=pablo;database=mexico;option=" & 1 + 2 + 8 + 32 + 2048 + 16384

chkConn.Open
chkRs.Open = chkConn.Execute("CHECK TABLE `inventory` MEDIUM") 'create a recordset using the results from CHECK TABLE

chkRs.MoveLast 'last row will contain the status
strMsgText = StrConv(chkRs("Msg_text"), vbProperCase)
strMsgType = StrConv(chkRs("Msg_type"), vbProperCase)

If chkRs("Msg_text") = "OK" Then
MsgBox "Check successful. No errors reported", vbInformation + vbOKOnly, App.Title
GoTo cleanup
Else
msg = "Severity: " & strMsgType & vbCrLf & _
"Message: " & strMsgText & vbCrLf & vbCrLf & _
"Please run DBRepair or contact technical support for assistance."
MsgBox msg, vbCritical, "DBCheck reported the following error(s):"
GoTo cleanup
End If

cleanup:
'Close database connections and release variables
chkRs.Close
chkConn.Close
Set chkRs = Nothing
Set chkConn = Nothing
End Sub

  Posted by eye chart on February 23, 2005
I changed up and improved the code posted by Stu Bray. Check out the change log for details.

-eyechart

-----


<?bash
#!/bin/bash
#
# #automysqlcheck.sh
#
# This is a small bash script that checks all mysql databases for errors
# and mails a log file to a specified email address. All variables are
# hardcoded for ease of use with cron. Any databases you wish not to check
# should be added to the DBEXCLUDE list, with a space in between each name.
#
# Note that DBEXCLUDE will only work with GNU sed, as BSD regular expressions
# on Darwin seem to have some trouble with word boundary anchors.
#
# original version by sbray@csc.uvic.ca, UVic Fine Arts 2004
#
# modified by eyechart AT gmail.com (see Change Log for details)
#
# Some of this code was inspired from automysqlbackup.sh.2.0
# http://sourceforge.net/projects/automysqlbackup/
#
#=====================================================================
# Change Log
#=====================================================================
#
# VER 1.1 - (2005-02-22)
#    Named script automysqlcheck.sh
#    Added PATH variable to make this script more CRON friendly
#    Removed the $DBTABLES loop and replaced it with single command
#      that executes the CHECK TABLE command on all tables in a given DB
#    Changed code to only check MyISAM and InnoDB tables
#    Cleaned up output to make the email prettier
#    Modified script to skip databases that have no tables
# VER 1 - (2004-09-24)
#    Initial release by sbray@csc.uvic.ca


# system variables (change these according to your system)
PATH=/usr/local/bin:/usr/bin:/bin:$PATH
USER
=root
PASSWORD
=
DBHOST=localhost
LOGFILE
=/var/log/automysqlcheck.log
MAILTO
=root@localhost
TYPE1
# extra params to CHECK_TABLE e.g. FAST
TYPE2=
CORRUPT=no # start by assuming no corruption
DBNAMES="all" # or a list delimited by space
DBEXCLUDE="" # or a list delimited by space

# I/O redirection...
touch $LOGFILE
exec 6
>&1
exec 
$LOGFILE # stdout redirected to $LOGFILE

echo -"AutoMySQLCheck: "
date
echo "---------------------------------------------------------"; echo; echo

# Get our list of databases to check...
# NOTE: the DBEXCLUDE feature seemed to only work with Linux regex, GNU sed
if test $DBNAMES "all" then
DBNAMES
="`mysql --user=$USER --password=$PASSWORD --batch -N -e "show databases"`"
for i in $DBEXCLUDE
do
  
DBNAMES=`echo $DBNAMES | sed "s/\b$i\b//g"`
done
fi

# Run through each database and execute our CHECK TABLE command for all tables
# in a single pass - eyechart
for i in $DBNAMES
do
  
# echo the database we are working on
  
echo "Database being checked:"
  
echo -"SHOW DATABASES LIKE '$i'" mysql --u$USER -p$PASSWORD $i; echo

  
# Check all tables in one pass, instead of a loop
  # Use GAWK to put in comma separators, use SED to remove trailing comma
  # Modified to only check MyISAM or InnoDB tables - eyechart
  
DBTABLES="`mysql --user=$USER --password=$PASSWORD $i --batch -N -e "show table status;" \
  | gawk 'BEGIN {ORS="
" } $2 == "MyISAM" || $2 == "InnoDB"{print $1}' | sed 's/, $//'`"

  
# Output in table form using -t option
  
if [ ! "$DBTABLES]
  
then
    
echo "NOTE:  There are no tables to check in the $i database - skipping..."; echo; echo
  else
    echo 
"CHECK TABLE $DBTABLES $TYPE1 $TYPE2mysql --u$USER -p$PASSWORD $i; echo; echo
  
fi
done

exec 1
>&6 6>&- # Restore stdout and close file descriptor #6

# test our logfile for corruption in the database...
for i in `cat $LOGFILE`
do
  if 
test $i "warning" then
  CORRUPT
=yes
  elif test $i 
"error" then
  CORRUPT
=yes
  fi
done

# Send off our results...
if test $CORRUPT "yes" then
cat $LOGFILE 
mail -"MySQL CHECK Log [ERROR FOUND] for $DBHOST-`date`" $MAILTO
else
cat $LOGFILE mail -"MySQL CHECK Log [PASSED OK] for $HOST-`date`" $MAILTO
fi
?>

  Posted by Ronald Laszlob on March 8, 2005
Hallo eyechart,

When you can not guarantee that no users work with the table, it is better to work with "FLUSH TABLES" and "UNLOCK TABLES".
So the line with "CHECK TABLE...." we can add:

echo "FLUSH TABLES WITH READ LOCK; CHECK TABLE $DBTABLES $TYPE1 $TYPE2; UNLOCK TABLES;" | mysql -t -u$USER -p$PASSWORD $i; echo; echo

I think this is safty.

Ronald Laszlob

  Posted by Matthew Haines on August 17, 2005
The above script has a flaw that prevents it from finding and reporting some corrupted tables.

It appears that if a table is completely corrupted, MyISAM does not appear in the 'Engine' column. Thus the script skips the table. Here is an example of output showing this case:

> show table status \G
[ ... snip ...]
*************************** 3. row ***************************
Name: residential
Engine: NULL
Version: NULL
Row_format: NULL
Rows: NULL
Avg_row_length: NULL
Data_length: NULL
Max_data_length: NULL
Index_length: NULL
Data_free: NULL
Auto_increment: NULL
Create_time: NULL
Update_time: NULL
Check_time: NULL
Collation: NULL
Checksum: NULL
Create_options: NULL
Comment: Can't open file: 'residential.MYI' (errno: 145)

Thus this table is simply missing from the results. If you have hundreds of tables, it is pretty easy to not realize that one is missing.

  Posted by Kristofer Widholm on October 28, 2006
Matthew Haines writes on August 17 2005 12:22pm:

>>The above script has a flaw that prevents it from finding and reporting some corrupted tables.

There are at least three scripts "above," all doing similar things. Which one are you refering to? Or all of them?

Thanks.
  Posted by Mickael Sundberg on October 29, 2006
I've made one small improvement to this script that is simple but I post it so the less geeky won't run into trouble.

I skipped the colour coding as the first backlash in "\`" $1 "\`" disappeared.

Check out the change log for details.

/ Mickael Sundberg

-----

#!/bin/bash
#
# #automysqlcheck.sh
#
# This is a small bash script that checks all mysql databases for errors
# and mails a log file to a specified email address. All variables are
# hardcoded for ease of use with cron. Any databases you wish not to check
# should be added to the DBEXCLUDE list, with a space in between each name.
#
# Note that DBEXCLUDE will only work with GNU sed, as BSD regular expressions
# on Darwin seem to have some trouble with word boundary anchors.
#
# original version by sbray@csc.uvic.ca, UVic Fine Arts 2004
#
# modified by eyechart AT gmail.com and Mickael Sundberg at mickael@pischows.se
# (see Change Log for details)
#
# Some of this code was inspired from automysqlbackup.sh.2.0
# http://sourceforge.net/projects/automysqlbackup/
#
#=====================================================================
# Change Log
#=====================================================================
#
# VER 1.2 - (2006-10-29)
# Added "\`" arround the tables in $DBTABLES, otherwise it'll create
# errors if tablenames containt characters like -.
# Modified by Mickael Sundberg
# VER 1.1 - (2005-02-22)
# Named script automysqlcheck.sh
# Added PATH variable to make this script more CRON friendly
# Removed the $DBTABLES loop and replaced it with single command
# that executes the CHECK TABLE command on all tables in a given DB
# Changed code to only check MyISAM and InnoDB tables
# Cleaned up output to make the email prettier
# Modified script to skip databases that have no tables
# Modified by eyechart
# VER 1 - (2004-09-24)
# Initial release by sbray@csc.uvic.ca

# system variables (change these according to your system)
PATH=/usr/local/bin:/usr/bin:/bin:$PATH
USER=root
PASSWORD=
DBHOST=localhost
LOGFILE=/var/log/automysqlcheck.log
MAILTO=root@localhost
TYPE1= # extra params to CHECK_TABLE e.g. FAST
TYPE2=
CORRUPT=no # start by assuming no corruption
DBNAMES="all" # or a list delimited by space
DBEXCLUDE="" # or a list delimited by space

# I/O redirection...
touch $LOGFILE
exec 6>&1
exec > $LOGFILE # stdout redirected to $LOGFILE

echo -n "AutoMySQLCheck: "
date
echo "---------------------------------------------------------"; echo; echo

# Get our list of databases to check...
# NOTE: the DBEXCLUDE feature seemed to only work with Linux regex, GNU sed
if test $DBNAMES = "all" ; then
DBNAMES="`mysql --user=$USER --password=$PASSWORD --batch -N -e "show databases"`"
for i in $DBEXCLUDE
do
DBNAMES=`echo $DBNAMES | sed "s/\b$i\b//g"`
done
fi

# Run through each database and execute our CHECK TABLE command for all tables
# in a single pass - eyechart
for i in $DBNAMES
do
# echo the database we are working on
echo "Database being checked:"
echo -n "SHOW DATABASES LIKE '$i'" | mysql -t -u$USER -p$PASSWORD $i; echo

# Check all tables in one pass, instead of a loop
# Use GAWK to put in comma separators, use SED to remove trailing comma
# Modified to only check MyISAM or InnoDB tables - eyechart
DBTABLES="`mysql --user=$USER --password=$PASSWORD $i --batch -N -e "show table status;" \
| gawk 'BEGIN {ORS=", " } $2 == "MyISAM" || $2 == "InnoDB"{print "\`" $1 "\`"}' | sed 's/, $//'`"

# Output in table form using -t option
if [ ! "$DBTABLES" ]
then
echo "NOTE: There are no tables to check in the $i database - skipping..."; echo; echo
else
echo "CHECK TABLE $DBTABLES $TYPE1 $TYPE2" | mysql -t -u$USER -p$PASSWORD $i; echo; echo
fi
done

exec 1>&6 6>&- # Restore stdout and close file descriptor #6

# test our logfile for corruption in the database...
for i in `cat $LOGFILE`
do
if test $i = "warning" ; then
CORRUPT=yes
elif test $i = "error" ; then
CORRUPT=yes
fi
done

# Send off our results...
if test $CORRUPT = "yes" ; then
cat $LOGFILE | mail -s "MySQL CHECK Log [ERROR FOUND] for $DBHOST-`date`" $MAILTO
else
cat $LOGFILE | mail -s "MySQL CHECK Log [PASSED OK] for $HOST-`date`" $MAILTO
fi
  Posted by Jake Carr on December 2, 2006
One small tweak to Mickael Sundberg's version of the script posted above, to get the script to pay attention to the DBHOST variable at the top:

#!/bin/bash
#
# #automysqlcheck.sh
#
# This is a small bash script that checks all mysql databases for errors
# and mails a log file to a specified email address. All variables are
# hardcoded for ease of use with cron. Any databases you wish not to check
# should be added to the DBEXCLUDE list, with a space in between each name.
#
# Note that DBEXCLUDE will only work with GNU sed, as BSD regular expressions
# on Darwin seem to have some trouble with word boundary anchors.
#
# original version by sbray@csc.uvic.ca, UVic Fine Arts 2004
#
# modified by eyechart AT gmail.com and Mickael Sundberg at mickael@pischows.se and Jake Carr jake-+AT+-websitesource-+DOT+-com
# (see Change Log for details)
#
# Some of this code was inspired from automysqlbackup.sh.2.0
# http://sourceforge.net/projects/automysqlbackup/
#
#=====================================================================
# Change Log
#=====================================================================
#
# VER 1.3 - (2006-12-02)
# Added --host=$DBHOST in mysql commands, so it's useful for non-localhost situations
# Jake Carr
# VER 1.2 - (2006-10-29)
# Added "\`" arround the tables in $DBTABLES, otherwise it'll create
# errors if tablenames containt characters like -.
# Modified by Mickael Sundberg
# VER 1.1 - (2005-02-22)
# Named script automysqlcheck.sh
# Added PATH variable to make this script more CRON friendly
# Removed the $DBTABLES loop and replaced it with single command
# that executes the CHECK TABLE command on all tables in a given DB
# Changed code to only check MyISAM and InnoDB tables
# Cleaned up output to make the email prettier
# Modified script to skip databases that have no tables
# Modified by eyechart
# VER 1 - (2004-09-24)
# Initial release by sbray@csc.uvic.ca

# system variables (change these according to your system)
PATH=/usr/local/bin:/usr/bin:/bin:$PATH
USER=root
PASSWORD=
DBHOST=localhost
LOGFILE=/var/log/automysqlcheck.log
MAILTO=root@localhost
TYPE1= # extra params to CHECK_TABLE e.g. FAST
TYPE2=
CORRUPT=no # start by assuming no corruption
DBNAMES="all" # or a list delimited by space
DBEXCLUDE="" # or a list delimited by space

echo -n "AutoMySQLCheck: "
date
echo "---------------------------------------------------------"; echo; echo

# Get our list of databases to check...
# NOTE: the DBEXCLUDE feature seemed to only work with Linux regex, GNU sed
if test $DBNAMES = "all" ; then
DBNAMES="`mysql --host=$DBHOST --user=$USER --password=$PASSWORD --batch -N -e "show databases"`"
for i in $DBEXCLUDE
do
DBNAMES=`echo $DBNAMES | sed "s/\b$i\b//g"`
done
fi

# Run through each database and execute our CHECK TABLE command for all tables
# in a single pass - eyechart
for i in $DBNAMES
do
# echo the database we are working on
echo "Database being checked:"
echo -n "SHOW DATABASES LIKE '$i'" | mysql -t --host=$DBHOST -u$USER -p$PASSWORD $i; echo

# Check all tables in one pass, instead of a loop
# Use GAWK to put in comma separators, use SED to remove trailing comma
# Modified to only check MyISAM or InnoDB tables - eyechart
DBTABLES="`mysql --host=$DBHOST --user=$USER --password=$PASSWORD $i --batch -N -e "show table status;" | gawk 'BEGIN {ORS=", " } $2 == "MyISAM" || $2 == "InnoDB"{print "\`" $1 "\`"}' | sed 's/, $//'`"

# Output in table form using -t option
if [ ! "$DBTABLES" ]
then
echo "NOTE: There are no tables to check in the $i database - skipping..."; echo; echo
else
echo "CHECK TABLE $DBTABLES $TYPE1 $TYPE2" | mysql --host=$DBHOST -t -u$USER -p$PASSWORD $i; echo; echo
fi
done

exec 1>&6 6>&- # Restore stdout and close file descriptor #6

# test our logfile for corruption in the database...
for i in `cat $LOGFILE`
do
if test $i = "warning" ; then
CORRUPT=yes
elif test $i = "error" ; then
CORRUPT=yes
fi
done

# Send off our results...
if test $CORRUPT = "yes" ; then
cat $LOGFILE | mail -s "MySQL CHECK Log [ERROR FOUND] for $DBHOST-`date`" $MAILTO
else
cat $LOGFILE | mail -s "MySQL CHECK Log [PASSED OK] for $DBHOST-`date`" $MAILTO
fi

  Posted by david mcanulty on December 29, 2006
There is an error in the above example that prevents logfile generation. The block below is missing:

# I/O redirection...
touch $LOGFILE
exec 6>&1
exec > $LOGFILE # stdout redirected to $LOGFILE

It should be between:
DBEXCLUDE="" # or a list delimited by space

and:
echo -n "AutoMySQLCheck: "

I also found it a more useful default to set $dbhost=localhost to
$dbhost=`hostname -s`
  Posted by Cary Petterborg on September 19, 2008
Starting with 5.0.51 or 5.0.67 the scripts above will have a problem when they perform a CHECK TABLE on the information_schema MyISAM tables, as these produce an error with the msg_text of:

Table upgrade required. Please do "REPAIR TABLE `/tmp/#sql_162_0`" to fix it!

This is a problem introduced in one of the two versions. Even with a completely clean install, and no newly created databases, this message will result from the check. Modifying the shell script to do something like (in context):

for i in $DBNAMES
do
if test $i = 'information_schema'
then
continue
fi
# echo the database we are working on
...

This will just exclude the information_schema database from the checks, thus preventing seeing the error that is not really an error. A similar fix could be done with the php script as well.
  Posted by Fabrizio La Rosa on October 18, 2010
In this version I have add the I/O redirection suggested by David and changed the db exclusion so that it also works with Darwin/Mac OS X

#!/bin/bash
#
# #automysqlcheck.sh
#
# This is a small bash script that checks all mysql databases for errors
# and mails a log file to a specified email address. All variables are
# hardcoded for ease of use with cron. Any databases you wish not to check
# should be added to the DBEXCLUDE list, with a space in between each name.
#
# original version by sbray@csc.uvic.ca, UVic Fine Arts 2004
#
# modified by eyechart AT gmail.com and Mickael Sundberg at mickael@pischows.se and Jake Carr jake-+AT+-websitesource-+DOT+-com
# (see Change Log for details)
#
#=====================================================================
# Change Log
#=====================================================================
#
# VER 1.4 - (2010-10-18)
# Added I/O redirection to $LOGFILE
# added flush & lock tables before check
# modified the database exclusion so that it works also with Darwin/Mac OS X
# Modified by Fabrizio La Rosa
# VER 1.3 - (2006-12-02)
# Added --host=$DBHOST in mysql commands, so it's useful for non-localhost situations
# Jake Carr
# VER 1.2 - (2006-10-29)
# Added "\`" arround the tables in $DBTABLES, otherwise it'll create
# errors if tablenames containt characters like -.
# Modified by Mickael Sundberg
# VER 1.1 - (2005-02-22)
# Named script automysqlcheck.sh
# Added PATH variable to make this script more CRON friendly
# Removed the $DBTABLES loop and replaced it with single command
# that executes the CHECK TABLE command on all tables in a given DB
# Changed code to only check MyISAM and InnoDB tables
# Cleaned up output to make the email prettier
# Modified script to skip databases that have no tables
# Modified by eyechart
# VER 1 - (2004-09-24)
# Initial release by sbray@csc.uvic.ca

# system variables (change these according to your system)
PATH=/usr/local/bin:/usr/bin:/bin:$PATH
USER=root
PASSWORD=
DBHOST=localhost
LOGFILE=/var/log/automysqlcheck.log
MAILTO=root@localhost
TYPE1= # extra params to CHECK_TABLE e.g. FAST
TYPE2=
CORRUPT=no # start by assuming no corruption
DBNAMES="all" # either "all" or a list delimited by space
DBEXCLUDE="" # either "" or a list delimited by space

# I/O redirection...
touch $LOGFILE
exec 6>&1
exec > $LOGFILE # stdout redirected to $LOGFILE
echo -n "AutoMySQLCheck: "
date
echo "---------------------------------------------------------"; echo; echo

# Get our list of databases to check...
if [ "$DBNAMES" = "all" ] ; then
DBNAMES=""
ALLDB="`mysql --host=$DBHOST --user=$USER --password=$PASSWORD --batch -N -e "show databases"`"
for i in $ALLDB ; do
INCLUDEDB=1
for j in $DBEXCLUDE ; do
if [ "$i" = "$j" ] ; then
INCLUDEDB=0
fi
done
if [ $INCLUDEDB -eq 1 ] ; then
DBNAMES=$DBNAMES" "$i
fi
done
fi

# Lock tables
mysql --host=$DBHOST --user=$USER --password=$PASSWORD --batch -N -e "flush tables with read lock; flush logs"
# Run through each database and execute our CHECK TABLE command for all tables
# in a single pass - eyechart
for i in $DBNAMES ; do
# echo the database we are working on
echo "Database being checked:"
echo -n "SHOW DATABASES LIKE '$i'" | mysql -t --host=$DBHOST -u$USER -p$PASSWORD $i; echo

# Check all tables in one pass, instead of a loop
# Use AWK to put in comma separators, use SED to remove trailing comma
# Modified to only check MyISAM or InnoDB tables - eyechart
DBTABLES="`mysql --host=$DBHOST --user=$USER --password=$PASSWORD $i --batch -N -e "show table status;" | awk 'BEGIN {ORS=", " } $2 == "MyISAM" || $2 == "InnoDB"{print "\`" $1 "\`"}' | sed 's/, $//'`"

# Output in table form using -t option
if [ ! "$DBTABLES" ] ; then
echo "NOTE: There are no tables to check in the $i database - skipping..."; echo; echo
else
echo "CHECK TABLE $DBTABLES $TYPE1 $TYPE2" | mysql --host=$DBHOST -t -u$USER -p$PASSWORD $i; echo; echo
fi
done
# Unlock tables
mysql --host=$DBHOST --user=$USER --password=$PASSWORD --batch -N -e "unlock tables"

exec 1>&6 6>&- # Restore stdout and close file descriptor #6

# test our logfile for corruption in the database...
for i in `cat $LOGFILE` ; do
if test $i = "warning" ; then
CORRUPT=yes
elif test $i = "error" ; then
CORRUPT=yes
fi
done

# Send off our results...
if test $CORRUPT = "yes" ; then
cat $LOGFILE | mail -s "MySQL CHECK Log [ERROR FOUND] for $DBHOST-`date`" $MAILTO
else
cat $LOGFILE | mail -s "MySQL CHECK Log [PASSED OK] for $DBHOST-`date`" $MAILTO
fi

Sign Up Login You must be logged in to post a comment.