Analyze Table
MySQL的Optimizer(優化元件)在優化SQL語句時,首先需要收集一些相關資訊,其中就包括表的cardinality(可以翻譯為“散列程度”),它表示某個索引對應的列包含多少個不同的值——如果cardinality大大少于資料的實際散列程度,那麼索引就基本失效了。
我們可以使用SHOW INDEX語句來檢視索引的散列程度
文法
ANALYZE TABLE 表名1 [,表名2…] ;
SHOW INDEX FROM user;
TABLE KEY_NAME COLUMN_NAME CARDINALITY
------- -------- ----------- -----------
user PRIMARY name 14
因為此時user表中不同的name數量遠遠多于14,索引基本失效。
下面我們通過Analyze Table語句來修複索引:
ANALYZE TABLE user;
SHOW INDEX FROM user;
結果是:
TABLE KEY_NAME COLUMN_NAME CARDINALITY
------- -------- ----------- -----------
user PRIMARY name 1000
此時索引已經修複,查詢效率大大提高。
需要注意的是,如果開啟了binlog,那麼Analyze Table的結果也會寫入binlog,我們可以在analyze和table之間添加關鍵字local取消寫入。
Checksum Table
資料在傳輸時,可能會發生變化,也有可能因為其它原因損壞,為了保證資料的一緻,我們可以計算checksum(校驗值)。
使用MyISAM引擎的表會把checksum存儲起來,稱為live checksum,當資料發生變化時,checksum會相應變化。
在執行Checksum Table時,可以在最後指定選項qiuck或是extended;quick表示傳回存儲的checksum值,而extended會重新計算checksum,如果沒有指定選項,則預設使用extended。
Checksum Table user;
Optimize Table
碎片産生的原因
(1)表的存儲會出現碎片化,每當删除了一行内容該段空間就會變為空白、被留白,而在一段時間内的大量删除操作,會使這種留白的空間變得比存儲清單内容所使用的空間更大;
(2)當執行插入操作時,MySQL會嘗試使用空白空間,但如果某個空白空間一直沒有被大小合适的資料占用,仍然無法将其徹底占用,就形成了碎片;
(3)當MySQL對資料進行掃描時,它掃描的對象實際是清單的容量需求上限,也就是資料被寫入的區域中處于峰值位置的部分;
Optimize Table語句對MyISAM和InnoDB類型的表都有效,但是,OPTILMIZE TABLE語句隻能優化表中的VARCHAR、BLOB或TEXT類型的字段。
如果表經常更新,就應當定期運作Optimize Table語句,保證效率。
1.檢視某個表的碎片
SHOW TABLE STATUS LIKE 'user';
結果中Data_free列的值就是碎片大小
2.列出所有已經産生碎片的表
select table_schema db, table_name, data_free, engine from information_schema.tables where table_schema not in ('information_schema', 'mysql') and data_free > 0;
在MySQL 5.5中,預設情況下所有表共享一個名為ibdata的中央表空間.此表空間中所有表的data_Free将報告相同的數字,即整個表空間中空閑頁面的空間量,而不僅僅是一個表.您還可以為每個表配置設定一個單獨的表空間(innodb_file_per_table = 1),對于單獨表空間中的表,您将看到data_free的每個表的不同值.
與Analyze Table一樣,Optimize Table也可以使用local來取消寫入binlog。
Optimize Table user;
innodb表可能提示:
Table does not support optimize, doing recreate + analyze instead
提示該表不支援 optimize,但是下邊有顯示OK.其實已經執行成功了。5.6.X的版本,其實已經支援Innodb了。
對于InnoDB的表、上面的内容并非報錯、這是MySQL會幫你映射到:alter table table_name engine='InnoDB';
OPTIMIZE 操作會暫時鎖住表,而且資料量越大,耗費的時間也越長,它畢竟不是簡單查詢操作.是以把 Optimize 指令放在程式中是不妥當的,不管設定的命中率多低,當通路量增大的時候,整體命中率也會上升,這樣肯定會對程式的運作效率造成很大影響.比較好的方式就是做個shell,定期檢查mysql中 information_schema.TABLES字段,檢視 DATA_FREE 字段,大于0話,就表示有碎片
建議:清除碎片操作會暫時鎖表,資料量越大,耗費的時間越長,可以做個腳本,定期在通路低谷時間執行,例如每周三淩晨,檢查DATA_FREE字段,大于自己認為的警戒值的話,就清理一次。
下面提供一個腳本參考:
//shell腳本如下:
mysql_user=root
mysql_pass=xxxx
time_log=/opt/database/time
databases=/opt/database/databases
mysql -u$mysql_user -p$mysql_pass -e "show databases" | grep -v "Database" > $databases
sed -i "s/information_schema//" $databases
sed -i "s/mysql//" $databases
sed -i "s/test//" $databases
sed -i "s/performance_schema//" $databases
databases1=$(cat /opt/database/databases)
for i in $databases1
do
echo "database $i staring"
tables=$(mysql $i -u$mysql_user -p$mysql_pass -e "show tables" | grep -v "Tables" > /opt/database/$i)
tablelist=$(cat /opt/database/$i)
echo "optimize database $i starting" >> $time_log
echo "$i start at $(date +[%Y/%m/%d/%H/%M/%S])" >> $time_log
for list in $tablelist
do
echo $list
mysql $i -u$mysql_user -p$mysql_pass -e "alter table $list engine=InnoDB"
done
echo "$i end as $(date +[%Y/%m/%d/%H/%M/%S])" >> $time_log
echo >> $time_log
done
Check Table
資料庫經常可能遇到錯誤,譬如資料寫入磁盤時發生錯誤,或是索引沒有同步更新,或是資料庫未關閉MySQL就停止了。
遇到這些情況,資料就可能發生錯誤:
Incorrect key file for table: ' '. Try to repair it.
此時,我們可以使用Check Table語句來檢查表及其對應的索引。
譬如我們運作
CHECK TABLE user;
結果是
TABLE OP MSG_TYPE MSG_TEXT
-------------- ----- -------- --------
dbname.users check status OK
MySQL會儲存表最近一次檢查的時間,每次運作check table都會存儲這些資訊:
執行
SELECT TABLE_NAME, CHECK_TIME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = 'user'
AND TABLE_SCHEMA = 'dbname'; /*dbname是資料庫名*/
結果是
TABLE_NAME CHECK_TIME
---------- -------------------
users 2017-04-25 12:44:25
Check Table還可以指定其它選項:
UPGRADE:用來測試在更早版本的MySQL中建立的表是否與目前版本相容。
QUICK:速度最快的選項,在檢查各列的資料時,不會檢查連結(link)的正确與否,如果沒有遇到什麼問題,可以使用這個選項。
FAST:隻檢查表是否正常關閉,如果在系統掉電之後沒有遇到嚴重問題,可以使用這個選項。
CHANGED:隻檢查上次檢查時間之後更新的資料。
MEDIUM:預設的選項,會檢查索引檔案和資料檔案之間的連結正确性。
EXTENDED:最慢的選項,會進行全面的檢查。
Repair Table
用于修複表,隻對MyISAM和ARCHIVE類型的表有效。
這條語句同樣可以指定選項:
QUICK:最快的選項,隻修複索引樹。
EXTENDED:最慢的選項,需要逐行重建索引。
USE_FRM:隻有當MYI檔案丢失時才使用這個選項,全面重建整個索引。