Каковы этапы обслуживания и производительности для сервера / базы данных Mysql? - PullRequest
2 голосов
/ 15 апреля 2010

Как и при обслуживании индекса, у нас есть индекс реорганизации / перестройки, статистика обновлений, сжатие файлов журнала базы данных, резервное копирование / восстановление базы данных на сервере MS SQL. Каковы этапы обслуживания и шаги по производительности для сервера / базы данных Mysql?

Ответы [ 2 ]

2 голосов
/ 08 сентября 2010
//--------------------------------------------------------------
//Here is a php script you can run weekly.  Just change the config info at the start
//--------------------------------------------------------------




//--------------------------------------------------------------
// BEGIN CONFIG  (I like to put this in a sep file, so I can just change the config for
// different database/servers
//--------------------------------------------------------------

//require_once ("mysql_maintenance_config.inc");  

  $_DB_Host = '127.0.0.1';          // your server ip
  $_DB_Name = 'database_name_goes_here';       // name of db to maintain       
  $_DB_User = 'database_user_goes_here';
  $_DB_Pass = 'pasword_goes_here';

  $_EMAIL_Admin_Addr = 'yourname@gmail.com';   // address to email errors/results to
                                               // php mail must be configured
  $_LOG_TABLE_NAME = 'log_mysql_maintenance';  // change this if you would like the results stored in a different table name
  $_EMAIL_Results = true;
  $_NO_WRITE_TO_BINLOG = false;  // only set to true if database is replicated
  $_SKIP_TABLES_WITH_LESS_THAN_X_ROWS = 100; // set to -1 to process all tables

//--------------------------------------------------------------
// END CONFIG  SECTION
//--------------------------------------------------------------



$total_query_time_for_page = 0;
$debug = false;

// set debug mode
if (isset($_GET['dxdb'])) 
{ 
    if ($_GET['dxdb']=='dcv') { $debug = true; }
} 

// open database connection
$db = mysql_connect ($_DB_Host, $_DB_User, $_DB_Pass);

if (!$db) 
{
    echo 'DATABASE_ERROR_MESSAGE';
    exit;   
}

if (mysql_select_db($_DB_Name, $db)==false)
{
    echo 'CANNOT_SELECT_DATABASE';
    exit;   
}


//--------------------------------------------------------------
// MYSQL MAINTENANCE TASKS
//--------------------------------------------------------------
// 1. Verify / Create Logging Table
// 2. Init Process Log
// 3. Build Table List
// 4. Check and Repair (MyISAM only) Tables if Necessary 
// 5. Optimize Tables 
// 6. Analyze Tables
// 7. Complete Logs and Email
//--------------------------------------------------------------

$_PROCESS_LOG = '';
$_PROCESS_ID = 0;
$_STARTED_ON = '';
$_COMPLETED_ON = 0;
$_TABLE_COUNT = 0;
$_TABLES_CHECKED = 0;
$_TABLES_OPTIMIZED = 0; 
$_TABLES_ANALYZED = 0; 
$_ERRORS_FOUND = 0; 
$_ERRORS_FIXED = 0; 
$_CURRENT_STATUS = '';                  
$_FINAL_STATUS = '';



//--------------------------------------------------------------
// 1. Verify / Create Logging Table  (log table name set in sql_maintenance_config.php)
//--------------------------------------------------------------

$lgx = dbGetReturnForSQL("SELECT COUNT(*) as ct FROM information_schema.tables WHERE table_schema = '$_DB_Name' AND table_name = '$_LOG_TABLE_NAME'",'',true);

if ($lgx==0)  // create logging table
{

    $sql = "CREATE TABLE $_LOG_TABLE_NAME (                              
             process_id int(11) NOT NULL auto_increment,                     
             started_on varchar(24) NOT NULL default '',                  
             completed_on varchar(24) NOT NULL default '',                  
             tables_checked int(11) NOT NULL default 0,                     
             tables_optimized int(11) NOT NULL default 0,                     
             tables_analyzed int(11) NOT NULL default 0,                     
             errors_found int(11) NOT NULL default 0,                     
             errors_fixed int(11) NOT NULL default 0,                     
             current_status varchar(32) NOT NULL default '',                    
             final_status varchar(32) NOT NULL default '',                    
             process_log varchar(20000) NOT NULL default '',                   
             PRIMARY KEY  (process_id)               
           ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8";

    dbExecuteSQL($sql);           

    $_PROCESS_LOG = "FIRST RUN - CREATING LOGGING TABLE \n -------------------------------------------------- \n";
}
else
{
    $_PROCESS_LOG = "LOG TABLE OK - BEGINING PROCESS \n -------------------------------------------------- \n";        

}




//--------------------------------------------------------------
// 2. Init Process Log
//--------------------------------------------------------------

$_STARTED_ON = getLogStamp();
$_CURRENT_STATUS = 'INIT PROCESS LOG';
$_FINAL_STATUS = 'IN PROCESS - NO ERRORS';

$sql = "INSERT INTO $_LOG_TABLE_NAME (started_on, current_status, final_status, process_log) VALUES ('$_STARTED_ON', '$_CURRENT_STATUS', '$_FINAL_STATUS', '$_PROCESS_LOG')";

$_PROCESS_ID = dbExecuteSQL($sql, true);

add2ProcessLog('Init Process Log', true);


if ($_NO_WRITE_TO_BINLOG)
{
    $_BINLOG = 'NO_WRITE_TO_BINLOG';
    add2ProcessLog('BINLOG WRITE DISABLED');   
}
else
{
    $_BINLOG = '';
    add2ProcessLog('BINLOG WRITE ENABLED');       
}




//--------------------------------------------------------------
// 3. Build Table List
//--------------------------------------------------------------

$_CURRENT_STATUS = 'BUILD TABLE LIST';

add2ProcessLog('Building Table List', true);

$sql = "SELECT TABLE_NAME, ENGINE, TABLE_ROWS 
        FROM information_schema.tables 
        WHERE table_schema = '$_DB_Name'";

$_TABLE_LIST = dbGetReturnForSQL($sql);

if ($_TABLE_LIST == 'x_no_data_x')  // no tables found
{
    add2ProcessLog("ERROR - NO TABLES FOUND", false);
    emailLogAndExit();
}
else
{
    $_TABLE_COUNT = count($_TABLE_LIST);   
    add2ProcessLog($_TABLE_COUNT . " tables found", true);
}





//--------------------------------------------------------------
// 4. Check and Repair (MyISAM only) Tables if Necessary 
//--------------------------------------------------------------

$_CURRENT_STATUS = 'CHECK AND REPAIR MYISAM TABLES';

add2ProcessLog("CHECK AND REPAIR MYISAM TABLES", true);

foreach($_TABLE_LIST AS $tbl_row)
{
    $tbl = $tbl_row['TABLE_NAME'];
    $eng = $tbl_row['ENGINE'];
    $rct = $tbl_row['TABLE_ROWS'];

    if ($tbl != $_LOG_TABLE_NAME && $eng == 'MyISAM')
    {
        $_TABLES_CHECKED++;

        add2ProcessLog("checking: $tbl");
        $sql = "CHECK TABLE $tbl";
        $rs = dbGetReturnForSQL($sql);      

        if ($rs == 'x_no_data_x')
        {
            emailLogAndExit("ERROR CHECKING TABLE: $tbl");
        }
        else
        {
            $rw = getLastRecord($rs);      
            if ($rw['Msg_text'] != 'OK')
            {
                $_ERRORS_FOUND++;
                add2ProcessLog('ERROR FOUND: ' . $rw['Msg_text'], true);

                // problem checking table - attempt to repair   
                $sql = "REPAIR TABLE $tbl";
                $rs = dbGetReturnForSQL($sql); 
                if ($rs == 'x_no_data_x')
                {
                    emailLogAndExit("ERROR REPAIRING TABLE: $tbl");
                }
                else
                {                
                    $rprw = getLastRecord($rs); 
                    if ($rw['Msg_text'] == 'OK')
                    {
                        $_ERRORS_FIXED++;
                        add2ProcessLog('ERROR REPAIRED on ' . $tbl);
                    }      
                    else   //could not repair error
                    {
                        emailLogAndExit("ERROR REPAIRING TABLE: $tbl | " . $rw['Msg_text']);    
                    }
                }
            }
            else
            {
                add2ProcessLog($tbl . ' checked ok');       
            }
        }
    }
}

add2ProcessLog("CHECK AND REPAIR MYISAM TABLES COMPLETED OK", true); 

//--------------------------------------------------------------
// 5. Optimize Tables 
//--------------------------------------------------------------

$_CURRENT_STATUS = 'OPTIMIZE TABLES'; 

add2ProcessLog("OPTIMIZE TABLES", true); 

foreach($_TABLE_LIST AS $tbl_row)
{
    $tbl = $tbl_row['TABLE_NAME'];
    $eng = $tbl_row['ENGINE'];
    $rct = $tbl_row['TABLE_ROWS'];

    if ($tbl != $_LOG_TABLE_NAME && intval($_SKIP_TABLES_WITH_LESS_THAN_X_ROWS)  'Jacks Function', '//#_reason_//#' => 'Because I said so')
    // $new_page:   if true, clear buffer and wrap in new page, if false, display err msg and exit  (note, for this to be used, ob_start() must have been called on the page first
    // $dev_dump:   any misc info you would like in the log, such as the query that caused the error.  this will not be displayed to the user
    // $email_err:  email address to send error to. if set to 'devteam' then the current group mailing addr will be used (i.e. devteam@thinklinklearning.com)
    //  FUTURE - might want to set a way to override this in the error_codes table to send to a specific developer during testing ( currently can only override to always email )
    // $log_only:   if true, do not display message, return to code  -could be used if we wanted to log here from perish() 

    global $db, $_EMAIL_Admin_Addr, $_CURRENT_STATUS, $_FINAL_STATUS;

    // log the error first

    $host_info = mysql_get_host_info();

    $rq = substr(var_export($_REQUEST,true),0,2000);
    $rq = mysql_real_escape_string($rq);

    // append last sql error to dev_dump

    $sql_dump = $dev_dump;

    // format sql

    $sql_dump = str_replace("\r\n",'',$sql_dump); 
    $sql_dump = str_replace("\n",'',$sql_dump);
    $sql_dump = str_replace("\t",'',$sql_dump);    

    $sql_dump = str_ireplace('SELECT',"\r\n SELECT",$sql_dump);
    $sql_dump = str_ireplace('FROM',"\r\n FROM",$sql_dump);
    $sql_dump = str_ireplace('WHERE',"\r\n WHERE",$sql_dump);
    $sql_dump = str_ireplace('INNER JOIN',"\r\n INNER JOIN",$sql_dump);
    $sql_dump = str_ireplace('LEFT JOIN',"\r\n LEFT JOIN",$sql_dump);
    $sql_dump = str_ireplace('AND',"\r\n AND",$sql_dump);
    $sql_dump = str_ireplace('GROUP BY',"\r\n GROUP BY",$sql_dump);
    $sql_dump = str_ireplace('ORDER BY',"\r\n ORDER BY",$sql_dump);
    $sql_dump = str_ireplace(',',"\r\n, ",$sql_dump);

    $sql_dump = str_replace('  ',' ',$sql_dump);
    $sql_dump = str_replace('  ',' ',$sql_dump);
    $sql_dump = str_replace('  ',' ',$sql_dump);

    $sql_err = mysql_error();
    $dev_dump = $sql_dump . "\r\n\r\n" . $sql_err;

    //echo " $sql_err$sql_dump";

    $dev_dump_to_mail = $host_info . "\r\n\r\n" . $dev_dump;
    $dev_dump = mysql_real_escape_string($dev_dump_to_mail . "\r\n\r\n" . $dev_dump);

    // get stack backtrace
    $a = debug_backtrace();
    $stack_tr = "stack trace: \r\n";
    $stack_tr .= "------------ \r\n"; 

    foreach($a as $k => $v)
    {
        $stack_tr .= "file: $v[file] \r\n"; 
        $stack_tr .= "line: $v[line] \r\n"; 
        $stack_tr .= "func: $v[function] \r\n"; 

        $args = $v['args'];

        foreach($args as $a_label => $a_val)
        {
            $stack_tr .= "$a_label => $a_val \r\n"; 
        }


        $stack_tr .= "//# \r\n";   
    }


    $pg = mysql_real_escape_string($_SERVER['PHP_SELF']);

    $stack_tr_to_mail = $stack_tr;
    $stack_tr = mysql_real_escape_string($stack_tr);

    if ($err_id=='') { $err_id = 'GENERAL_ERROR'; }

    $email_err = $_EMAIL_Admin_Addr;  // always email errors to admin
    $err_html = '';

    // email error if requested
    if ($email_err!='')
    {   
        $pg = explode('/', $pg);
        $pg = $pg[count($pg)-1];

        if (strpos(strtoupper($_SERVER['SERVER_NAME']),'DEV')>2) { $fsrv = ' (DEV)'; } else { $fsrv = ''; }

        mail($email_err, "Error$fsrv: $pg - $err_id ", 
"PHP_SELF\t $_SERVER[PHP_SELF]
\n\n------------------------------------\n\n
error_id:\t $err_id\n\n
\n\n------------------------------------\n\n
sql_err:\t $sql_err \n\n
\n\n------------------------------------\n\n
sql_dump:\n\n $sql_dump \n\n
\n\n------------------------------------\n\n
last_db_host:\t $host_info\n\n
\n\n------------------------------------\n\n
stack_tr:\n 
$stack_tr_to_mail\n\n
\n\n------------------------------------\n\n
dev_dump:\n
$dev_dump_to_mail\n\n
\n\n------------------------------------\n\n
err_log_key: $err_log_key ");
    }        


    // update process log
    $_CURRENT_STATUS = 'ERROR';
    $_FINAL_STATUS = 'ERROR';
    add2ProcessLog('ERROR - ' . $sql_err, true);

    echo 'ERROR: ' . $pg . ' - ' . $sql_err;    

    exit();

}  

//--------------------------------------------------------------

function getRequestVar($fieldname,$defaultvalue,$numeric_only=false,$prep_for_sql_insert=false)
{
    $rtn = '';

    if (isset($_POST[$fieldname]))
    {
        $rtn = $_POST[$fieldname];
    }
    else
    {
        if (isset($_GET[$fieldname]))
        {
            $rtn = $_GET[$fieldname];
        }
        else
        {
            $rtn = $defaultvalue;
        }
    }

    if ($numeric_only==true)
    {
        if (is_numeric($rtn)==false) {$rtn = $defaultvalue;}   
    }

    if ($prep_for_sql_insert==true)
    {
        $rtn = "'" . mysql_real_escape_string($rtn) . "'";   
    }

    return($rtn);

}

//--------------------------------------------------------------

function prepForSQL($rtn_val, $numeric_only=false)
{

    if ($numeric_only==true)
    {
        if (is_numeric($rtn_val)==false) {$rtn_val = -999;}   
    }
    else
    {
        // remove chrs we dont allow in the system
        $rtn_val = str_replace("'","",$rtn_val);
        $rtn_val = str_replace('"',"",$rtn_val);
        $rtn_val = str_replace("\\","",$rtn_val);
        $rtn_val = str_replace(';',"",$rtn_val);
        $rtn_val = "'" . mysql_real_escape_string($rtn_val) . "'";   
    }

    return($rtn_val);

}

//--------------------------------------------------------------

function dbGetReturnForSQL($sql, $field_for_key = '', $get_scalar_value = false, $default_value = 'x_no_data_x')
{
    /*  this function works for scalar, one row and multi row queries

        if $field_for_key = '' then use index

        if $get_scalar_value = true then return 1st row in array only (not nested in row array) or if only 1 value return value only (no array)  - first row only must be set to true 

        if no data is present $default_value will be returned, if blank, 'x_no_data_x' will be returned

        $error_id_on_fail, error id to pass to displayErrorMsg (defaults to GENERAL_ERROR)



    */

    global $db, $debug, $total_query_time_for_page;

    $loc_ptr = 0;
    $loc_key = '';
    $loc_arr = array();
    $loc_val = '';
    $use_srv = 'MASTER';
    $error_id_on_fail = '';

    if ( $debug ) {
        echo "QUERY:

\n\n" . ereg_replace("\t", " ", $sql) . "\n
\ n

\ n "; } if ($ debug) {$ start_time = microtime (true); } $ result = mysql_query ($ sql, $ db) ИЛИ displayErrorMsg ($ error_id_on_fail, '', '', false, $ sql, 'richard.varno @ gmail.com', false); if ($ debug) { $ end_time = microtime (true); $ row_rtn = mysql_num_rows ($ result); $ qry_time = $ end_time - $ start_time; $ total_query_time_for_page = $ total_query_time_for_page + $ qry_time; $ host_info = mysql_get_host_info (); echo " $ row_rtn строк возвращено за $ qry_time секунд из $ host_info ($ use_srv)

общее время запроса: $ total_query_time_for_page секунд

\ n" ; } while ($ rw = mysql_fetch_assoc ($ result)) { if ($ get_scalar_value == true) { // показать возвращаемое значение, если debug = true if ($ debug) { echo "Скалярное значение
\ n \ n"; foreach ($ rw как $ fld_key => $ fld_val) { echo " $ fld_key $ fld_val \ n"; } эхо "\ n"; } if (count ($ rw) == 1) { $ rw_key = array_keys ($ rw); $ loc_val = $ rw [$ rw_key [0]]; mysql_free_result ($ результат); вернуться ($ loc_val); } еще { mysql_free_result ($ результат); возврата ($ RW); } } еще { if ($ field_for_key == '') // использовать указатель индекса { $ loc_key = $ loc_ptr; } еще // использовать поле { $ loc_key = $ rw [$ field_for_key]; } $ loc_arr [$ loc_key] = $ rw; $ Loc_ptr ++; } } mysql_free_result ($ результат); // если результатов не найдено, вернуть значение по умолчанию если ($ loc_ptr == 0) { $ loc_arr = $ default_value; } еще { // показать возвращаемое значение, если debug = true (только первые 50 строк) if ($ debug) { если ($ row_rtn> 50) { echo "Отображение строк от 1 до $ row_rtn из $ row_rtn
\ n"; $ max_row_to_display = 49; } еще { echo "Отображение строк от 1 до $ row_rtn из $ row_rtn
\ n"; $ max_row_to_display = $ row_rtn-1; } эхо "\ n"; // показать заголовки $ loc_arr_keys = array_keys ($ loc_arr); $ rw = $ loc_arr [$ loc_arr_keys [0]]; эхо "\ n"; foreach ($ rw как $ fld_key => $ fld_val) { echo " $ fld_key \ n"; } эхо "\ n"; // показать данные $ cur_row = 0; foreach ($ loc_arr как $ ptr => $ row) { эхо "\ n"; foreach ($ rw как $ fld_key => $ fld_val) { echo "$ row [$ fld_key] \ n"; } эхо "\ n"; $ Cur_row ++; if ($ cur_row> $ max_row_to_display) {break; } } эхо "\ n"; } } возврат ($ loc_arr); } // ------------------------------------------------ -------------- функция dbExecuteSQL ($ sql, $ return_insert_id = false) { / * эта функция будет выполняться и оператор SQL для базы данных master и возвращать либо затронутые строки, либо идентификатор вставки, если требуется $ error_id_on_fail, идентификатор ошибки для передачи в displayErrorMsg (по умолчанию GENERAL_ERROR) * / global $ db, $ debug, $ total_query_time_for_page; $ loc_ptr = 0; $ loc_insert_id = 0; $ loc_rows_affered = 0; $ error_id_on_fail = ''; if ($ debug) { echo " QUERY:


\ n
\n" . ereg_replace("\t", " ", $sql) . "\n
\ n

\ n"; }if ($ debug) {$ start_time = microtime (true); } $ result = mysql_query ($ sql, $ db) ИЛИ displayErrorMsg ($ error_id_on_fail, '', '', false, $ sql, 'richard.varno @ gmail.com', false); $ loc_insert_id = mysql_insert_id ($ db); $ loc_rows_affered = mysql_affered_rows ($ db); $ use_srv = 'MASTER'; if ($ debug) { $ end_time = microtime (true); $ qry_time = $ end_time - $ start_time; $ total_query_time_for_page = $ total_query_time_for_page + $ qry_time; $ host_info = mysql_get_host_info ($ db); echo "Строки $ loc_rows_affered затронуты за $ qry_time секунд из $ host_info ($ use_srv)

общее время запроса: $ total_query_time_for_page секунд

\ n"; } if ($ return_insert_id == true) {return ($ loc_insert_id); } else {return ($ loc_rows_affered); } } // ------------------------------------------------ --------------
2 голосов
/ 15 апреля 2010

ANALYZE TABLE отсканирует ключи и сохранит данные, которые помогут будущим СОЕДИНЕНИЯМ. Я не знаю, насколько она полезна / нужна, но держу пари, что это, безусловно, зависит от того, какова ваша типичная рабочая нагрузка на БД и структура таблицы.

OPTIMIZE TABLE будет дефрагментировать ваши таблицы и восстанавливать неиспользуемое пространство, но, как вы можете прочитать в документации, это часто вообще не нужно.

Вы можете вызывать их через SQL или с помощью инструмента mysqlcheck .

Хотя в большинстве случаев это не нужно, я обычно назначаю mysqlcheck -Aao в периоды низкой активности (в моем случае это означает, что в выходные дни).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...