十年網(wǎng)站開發(fā)經(jīng)驗 + 多家企業(yè)客戶 + 靠譜的建站團(tuán)隊
量身定制 + 運營維護(hù)+專業(yè)推廣+無憂售后,網(wǎng)站問題一站解決
有兩種方法,一種方法使用mysql的check table和repair table 的sql語句,另一種方法是使用MySQL提供的多個myisamchk, isamchk數(shù)據(jù)檢測恢復(fù)工具。前者使用起來比較簡便。推薦使用。
目前創(chuàng)新互聯(lián)已為千余家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)絡(luò)空間、綿陽服務(wù)器托管、企業(yè)網(wǎng)站設(shè)計、納溪網(wǎng)站維護(hù)等服務(wù),公司將堅持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。
1. check table 和 repair table
登陸mysql 終端:
mysql -uxxxxx -p dbname
check table tabTest;
如果出現(xiàn)的結(jié)果說Status是OK,則不用修復(fù),如果有Error,可以用:
repair table tabTest;
進(jìn)行修復(fù),修復(fù)之后可以在用check table命令來進(jìn)行檢查。在新版本的phpMyAdmin里面也可以使用check/repair的功能。
2. myisamchk, isamchk
其中myisamchk適用于MYISAM類型的數(shù)據(jù)表,而isamchk適用于ISAM類型的數(shù)據(jù)表。這兩條命令的主要參數(shù)相同,一般新的系統(tǒng)都使用MYISAM作為缺省的數(shù)據(jù)表類型,這里以myisamchk為例子進(jìn)行說明。當(dāng)發(fā)現(xiàn)某個數(shù)據(jù)表出現(xiàn)問題時可以使用:
myisamchk tablename.MYI
進(jìn)行檢測,如果需要修復(fù)的話,可以使用:
myisamchk -of tablename.MYI
關(guān)于myisamchk的詳細(xì)參數(shù)說明,可以參見它的使用幫助。需要注意的時在進(jìn)行修改時必須確保MySQL服務(wù)器沒有訪問這個數(shù)據(jù)表,保險的情況下是最好在進(jìn)行檢測時把MySQL服務(wù)器Shutdown掉。
-----------------------------
另外可以把下面的命令放在你的rc.local里面啟動MySQL服務(wù)器前:
[ -x /tmp/mysql.sock ] /pathtochk/myisamchk -of /DATA_DIR/*/*.MYI
其中的/tmp/mysql.sock是MySQL監(jiān)聽的Sock文件位置,對于使用RPM安裝的用戶應(yīng)該是/var/lib/mysql/mysql.sock,對于使用源碼安裝則是/tmp/mysql.sock可以根據(jù)自己的實際情況進(jìn)行變更,而pathtochk則是myisamchk所在的位置,DATA_DIR是你的MySQL數(shù)據(jù)庫存放的位置。
需要注意的時,如果你打算把這條命令放在你的rc.local里面,必須確認(rèn)在執(zhí)行這條指令時MySQL服務(wù)器必須沒有啟動!檢測修復(fù)所有數(shù)據(jù)庫(表)
先來說說臨時表的概念。 臨時表顧名思義,就是臨時的,用完銷毀掉的表。 數(shù)據(jù)既可以保存在臨時的文件系統(tǒng)上,也可以保存在固定的磁盤文件系統(tǒng)上。 臨時表有下面幾種:
1全局臨時表
這種臨時表從數(shù)據(jù)庫實例啟動后開始生效,在數(shù)據(jù)庫實例銷毀后失效。在MySQL里面這種臨時表對應(yīng)的是內(nèi)存表,即memory引擎。
2會話級別臨時表
這種臨時表在用戶登錄系統(tǒng)成功后生效,在用戶退出時失效。在MySQL里的臨時表指的就是以 create temporary table 這樣的關(guān)鍵詞創(chuàng)建的表。
3事務(wù)級別臨時表
這種臨時表在事務(wù)開始時生效,事務(wù)提交或者回滾后失效。 在MySQL里面沒有這種臨時表,必須利用會話級別的臨時表間接實現(xiàn)。
4檢索級別臨時表
這種臨時表在SQL語句執(zhí)行之間產(chǎn)生,執(zhí)行完畢后失效。 在MySQL里面這種臨時表不是很固定,跟隨MySQL默認(rèn)存儲引擎來變化。比如默認(rèn)存儲引擎是MyISAM,臨時表的引擎就是MyISAM,并且文件生成形式以及數(shù)據(jù)運作形式和MyISAM一樣,只是數(shù)據(jù)保存在內(nèi)存里;如果默認(rèn)引擎是INNODB,那么臨時表的引擎就是INNODB,此時它的所有信息都保存在共享表空間ibdata里面。
MySQL 5.7對于InnoDB存儲引擎的臨時表空間做了優(yōu)化。在MySQL 5.7之前,INNODB引擎的臨時表都保存在ibdata里面,而ibdata的貪婪式磁盤占用導(dǎo)致臨時表的創(chuàng)建與刪除對其他正常表產(chǎn)生非常大的性能影響。在MySQL5.7中,對于臨時表做了下面兩個重要方面的優(yōu)化:
MySQL5.7 把臨時表的數(shù)據(jù)以及回滾信息(僅限于未壓縮表)從共享表空間里面剝離出來,形成自己單獨的表空間,參數(shù)為innodb_temp_data_file_path。
在MySQL5.7 中把臨時表的相關(guān)檢索信息保存在系統(tǒng)信息表中:information_schema.innodb_temp_table_info.?而MySQL 5.7之前的版本想要查看臨時表的系統(tǒng)信息是沒有太好的辦法。
需要注意的一點就是,雖然INNODB臨時表有自己的表空間,但是目前還不能自己定義臨時表空間文件的保存路徑,只能是繼承innodb_data_home_dir。此時如果想要拿其他的磁盤,比如內(nèi)存盤來充當(dāng)臨時表空間的保存地址,只能用老辦法,做軟鏈。舉個小例子:
我現(xiàn)在用的OS是 Ubuntu12.X,想用tmpfs文件系統(tǒng)充當(dāng)臨時表空間,
root@ytt-master-VirtualBox:/usr/local/mysql/data#?ln -s/run/shm/ /usr/local/mysql/data/tmp_space2
root@ytt-master-VirtualBox:/usr/local/mysql/data#ls -l | grep 'shm'
lrwxrwxrwx1 root root 9 Nov 13 10:28tmp_space2 - /run/shm/
然后把
innodb_temp_data_file_path=tmp_space2/ibtmp2:200M:autoextend
添加到my.cnf里的[mysqld]下面一行
重啟MySQL服務(wù)后,
mysqlselect @@innodb_temp_data_file_path\G
***************************1. row ***************************
@@innodb_temp_data_file_path:tmp_space2/ibtmp2:200M:autoextend
1 rowin set (0.00 sec)
先寫一個批量創(chuàng)建臨時表的存儲過程:
DELIMITER$$
USE`t_girl`$$
DROPPROCEDURE IF EXISTS `sp_create_temporary_table`$$
CREATEDEFINER=`root`@`localhost` PROCEDURE `sp_create_temporary_table`(
IN f_cnt INT UNSIGNED )
BEGIN
DECLARE i INT UNSIGNED DEFAULT 1;
WHILE i = f_cnt
DO
SET @stmt = CONCAT('create temporarytable tmp',i,' ( id int, tmp_desc varchar(60));');
PREPARE s1 FROM @stmt;
EXECUTE s1;
SET i = i + 1;
END WHILE;
DROP PREPARE s1;
END$$
DELIMITER;
現(xiàn)在來創(chuàng)建10張臨時表:
mysqlcall sp_create_temporary_table(10);
QueryOK, 0 rows affected (0.07 sec)
如果在以前,我們只知道創(chuàng)建了10張臨時表,但是只能憑記憶或者手工記錄下來臨時表的名字等信息。
現(xiàn)在可以直接從數(shù)據(jù)字典里面檢索相關(guān)數(shù)據(jù)。
mysql?select * frominformation_schema.innodb_temp_table_info;
+----------+--------------+--------+-------+----------------------+---------------+
|TABLE_ID | NAME | N_COLS | SPACE| PER_TABLE_TABLESPACE | IS_COMPRESSED |
+----------+--------------+--------+-------+----------------------+---------------+
| 56 | #sql1705_2_9 | 5 | 36 | FALSE | FALSE |
| 55 | #sql1705_2_8 | 5 | 36 | FALSE |FALSE |
| 54 | #sql1705_2_7 | 5 | 36 | FALSE | FALSE |
| 53 | #sql1705_2_6 | 5 | 36 | FALSE | FALSE |
| 52 | #sql1705_2_5 | 5 | 36 | FALSE |FALSE |
| 51 | #sql1705_2_4 | 5 | 36 | FALSE | FALSE |
| 50 | #sql1705_2_3 | 5 | 36 | FALSE | FALSE |
| 49 | #sql1705_2_2 | 5 | 36 | FALSE |FALSE |
| 48 | #sql1705_2_1 | 5 | 36 | FALSE | FALSE |
| 47 | #sql1705_2_0 | 5 | 36 | FALSE | FALSE |
+----------+--------------+--------+-------+----------------------+---------------+
10rows in set (0.00 sec)
功能性我就寫到這里,大家性能方面如果有興趣可以找時間去測試。
都新年了,還出問題了,還想說新年快樂呢!哇哈哈。如下是官方解釋:
--------------------------------------------------------------------------------------------
Sending data
The thread is reading and processing rows for a SELECT statement, and sending data to the client. Because operations occurring during this this state tend to perform large amounts of disk access (reads), it is often the longest-running state over the lifetime of a given query.
-------------
換句話說,你的sql查詢消耗的IO太多了,磁盤利用的太高了。
第一:優(yōu)化SQL,建立索引啦,更改表設(shè)計啦,這些。
第二:對于經(jīng)常查詢的數(shù)據(jù)如果不多可采用mysql內(nèi)存表
第三:CRUD優(yōu)先級導(dǎo)致select征用。提高查詢優(yōu)先級這個不建議使用。
第四:使用inodb引擎
第五:分區(qū),減少鎖競爭。
。。。。
不說了,自己優(yōu)化查詢速度就可以解決這個問題。
在開始演示之前,我們先介紹下兩個概念。
概念一,數(shù)據(jù)的可選擇性基數(shù),也就是常說的cardinality值。
查詢優(yōu)化器在生成各種執(zhí)行計劃之前,得先從統(tǒng)計信息中取得相關(guān)數(shù)據(jù),這樣才能估算每步操作所涉及到的記錄數(shù),而這個相關(guān)數(shù)據(jù)就是cardinality。簡單來說,就是每個值在每個字段中的唯一值分布狀態(tài)。
比如表t1有100行記錄,其中一列為f1。f1中唯一值的個數(shù)可以是100個,也可以是1個,當(dāng)然也可以是1到100之間的任何一個數(shù)字。這里唯一值越的多少,就是這個列的可選擇基數(shù)。
那看到這里我們就明白了,為什么要在基數(shù)高的字段上建立索引,而基數(shù)低的的字段建立索引反而沒有全表掃描來的快。當(dāng)然這個只是一方面,至于更深入的探討就不在我這篇探討的范圍了。
概念二,關(guān)于HINT的使用。
這里我來說下HINT是什么,在什么時候用。
HINT簡單來說就是在某些特定的場景下人工協(xié)助MySQL優(yōu)化器的工作,使她生成最優(yōu)的執(zhí)行計劃。一般來說,優(yōu)化器的執(zhí)行計劃都是最優(yōu)化的,不過在某些特定場景下,執(zhí)行計劃可能不是最優(yōu)化。
比如:表t1經(jīng)過大量的頻繁更新操作,(UPDATE,DELETE,INSERT),cardinality已經(jīng)很不準(zhǔn)確了,這時候剛好執(zhí)行了一條SQL,那么有可能這條SQL的執(zhí)行計劃就不是最優(yōu)的。為什么說有可能呢?
來看下具體演示
譬如,以下兩條SQL,
A:
select * from t1 where f1 = 20;
B:
select * from t1 where f1 = 30;
如果f1的值剛好頻繁更新的值為30,并且沒有達(dá)到MySQL自動更新cardinality值的臨界值或者說用戶設(shè)置了手動更新又或者用戶減少了sample page等等,那么對這兩條語句來說,可能不準(zhǔn)確的就是B了。
這里順帶說下,MySQL提供了自動更新和手動更新表cardinality值的方法,因篇幅有限,需要的可以查閱手冊。
那回到正題上,MySQL 8.0 帶來了幾個HINT,我今天就舉個index_merge的例子。
示例表結(jié)構(gòu):
mysql desc t1;+------------+--------------+------+-----+---------+----------------+| Field ? ? ?| Type ? ? ? ? | Null | Key | Default | Extra ? ? ? ? ?|+------------+--------------+------+-----+---------+----------------+| id ? ? ? ? | int(11) ? ? ?| NO ? | PRI | NULL ? ?| auto_increment || rank1 ? ? ?| int(11) ? ? ?| YES ?| MUL | NULL ? ?| ? ? ? ? ? ? ? ?|| rank2 ? ? ?| int(11) ? ? ?| YES ?| MUL | NULL ? ?| ? ? ? ? ? ? ? ?|| log_time ? | datetime ? ? | YES ?| MUL | NULL ? ?| ? ? ? ? ? ? ? ?|| prefix_uid | varchar(100) | YES ?| ? ? | NULL ? ?| ? ? ? ? ? ? ? ?|| desc1 ? ? ?| text ? ? ? ? | YES ?| ? ? | NULL ? ?| ? ? ? ? ? ? ? ?|| rank3 ? ? ?| int(11) ? ? ?| YES ?| MUL | NULL ? ?| ? ? ? ? ? ? ? ?|+------------+--------------+------+-----+---------+----------------+7 rows in set (0.00 sec)
表記錄數(shù):
mysql select count(*) from t1;+----------+| count(*) |+----------+| ? ?32768 |+----------+1 row in set (0.01 sec)
這里我們兩條經(jīng)典的SQL:
SQL C:
select * from t1 where rank1 = 1 or rank2 = 2 or rank3 = 2;
SQL D:
select * from t1 where rank1 =100 ?and rank2 =100 ?and rank3 =100;
表t1實際上在rank1,rank2,rank3三列上分別有一個二級索引。
那我們來看SQL C的查詢計劃。
顯然,沒有用到任何索引,掃描的行數(shù)為32034,cost為3243.65。
mysql explain ?format=json select * from t1 ?where rank1 =1 or rank2 = 2 or rank3 = 2\G*************************** 1. row ***************************EXPLAIN: { ?"query_block": { ? ?"select_id": 1, ? ?"cost_info": { ? ? ?"query_cost": "3243.65" ? ?}, ? ?"table": { ? ? ?"table_name": "t1", ? ? ?"access_type": "ALL", ? ? ?"possible_keys": [ ? ? ? ?"idx_rank1", ? ? ? ?"idx_rank2", ? ? ? ?"idx_rank3" ? ? ?], ? ? ?"rows_examined_per_scan": 32034, ? ? ?"rows_produced_per_join": 115, ? ? ?"filtered": "0.36", ? ? ?"cost_info": { ? ? ? ?"read_cost": "3232.07", ? ? ? ?"eval_cost": "11.58", ? ? ? ?"prefix_cost": "3243.65", ? ? ? ?"data_read_per_join": "49K" ? ? ?}, ? ? ?"used_columns": [ ? ? ? ?"id", ? ? ? ?"rank1", ? ? ? ?"rank2", ? ? ? ?"log_time", ? ? ? ?"prefix_uid", ? ? ? ?"desc1", ? ? ? ?"rank3" ? ? ?], ? ? ?"attached_condition": "((`ytt`.`t1`.`rank1` = 1) or (`ytt`.`t1`.`rank2` = 2) or (`ytt`.`t1`.`rank3` = 2))" ? ?} ?}}1 row in set, 1 warning (0.00 sec)
我們加上hint給相同的查詢,再次看看查詢計劃。
這個時候用到了index_merge,union了三個列。掃描的行數(shù)為1103,cost為441.09,明顯比之前的快了好幾倍。
mysql explain ?format=json select /*+ index_merge(t1) */ * from t1 ?where rank1 =1 or rank2 = 2 or rank3 = 2\G*************************** 1. row ***************************EXPLAIN: { ?"query_block": { ? ?"select_id": 1, ? ?"cost_info": { ? ? ?"query_cost": "441.09" ? ?}, ? ?"table": { ? ? ?"table_name": "t1", ? ? ?"access_type": "index_merge", ? ? ?"possible_keys": [ ? ? ? ?"idx_rank1", ? ? ? ?"idx_rank2", ? ? ? ?"idx_rank3" ? ? ?], ? ? ?"key": "union(idx_rank1,idx_rank2,idx_rank3)", ? ? ?"key_length": "5,5,5", ? ? ?"rows_examined_per_scan": 1103, ? ? ?"rows_produced_per_join": 1103, ? ? ?"filtered": "100.00", ? ? ?"cost_info": { ? ? ? ?"read_cost": "330.79", ? ? ? ?"eval_cost": "110.30", ? ? ? ?"prefix_cost": "441.09", ? ? ? ?"data_read_per_join": "473K" ? ? ?}, ? ? ?"used_columns": [ ? ? ? ?"id", ? ? ? ?"rank1", ? ? ? ?"rank2", ? ? ? ?"log_time", ? ? ? ?"prefix_uid", ? ? ? ?"desc1", ? ? ? ?"rank3" ? ? ?], ? ? ?"attached_condition": "((`ytt`.`t1`.`rank1` = 1) or (`ytt`.`t1`.`rank2` = 2) or (`ytt`.`t1`.`rank3` = 2))" ? ?} ?}}1 row in set, 1 warning (0.00 sec)
我們再看下SQL D的計劃:
不加HINT,
mysql explain format=json select * from t1 where rank1 =100 and rank2 =100 and rank3 =100\G*************************** 1. row ***************************EXPLAIN: { ?"query_block": { ? ?"select_id": 1, ? ?"cost_info": { ? ? ?"query_cost": "534.34" ? ?}, ? ?"table": { ? ? ?"table_name": "t1", ? ? ?"access_type": "ref", ? ? ?"possible_keys": [ ? ? ? ?"idx_rank1", ? ? ? ?"idx_rank2", ? ? ? ?"idx_rank3" ? ? ?], ? ? ?"key": "idx_rank1", ? ? ?"used_key_parts": [ ? ? ? ?"rank1" ? ? ?], ? ? ?"key_length": "5", ? ? ?"ref": [ ? ? ? ?"const" ? ? ?], ? ? ?"rows_examined_per_scan": 555, ? ? ?"rows_produced_per_join": 0, ? ? ?"filtered": "0.07", ? ? ?"cost_info": { ? ? ? ?"read_cost": "478.84", ? ? ? ?"eval_cost": "0.04", ? ? ? ?"prefix_cost": "534.34", ? ? ? ?"data_read_per_join": "176" ? ? ?}, ? ? ?"used_columns": [ ? ? ? ?"id", ? ? ? ?"rank1", ? ? ? ?"rank2", ? ? ? ?"log_time", ? ? ? ?"prefix_uid", ? ? ? ?"desc1", ? ? ? ?"rank3" ? ? ?], ? ? ?"attached_condition": "((`ytt`.`t1`.`rank3` = 100) and (`ytt`.`t1`.`rank2` = 100))" ? ?} ?}}1 row in set, 1 warning (0.00 sec)
加了HINT,
mysql explain format=json select /*+ index_merge(t1)*/ * from t1 where rank1 =100 and rank2 =100 and rank3 =100\G*************************** 1. row ***************************EXPLAIN: { ?"query_block": { ? ?"select_id": 1, ? ?"cost_info": { ? ? ?"query_cost": "5.23" ? ?}, ? ?"table": { ? ? ?"table_name": "t1", ? ? ?"access_type": "index_merge", ? ? ?"possible_keys": [ ? ? ? ?"idx_rank1", ? ? ? ?"idx_rank2", ? ? ? ?"idx_rank3" ? ? ?], ? ? ?"key": "intersect(idx_rank1,idx_rank2,idx_rank3)", ? ? ?"key_length": "5,5,5", ? ? ?"rows_examined_per_scan": 1, ? ? ?"rows_produced_per_join": 1, ? ? ?"filtered": "100.00", ? ? ?"cost_info": { ? ? ? ?"read_cost": "5.13", ? ? ? ?"eval_cost": "0.10", ? ? ? ?"prefix_cost": "5.23", ? ? ? ?"data_read_per_join": "440" ? ? ?}, ? ? ?"used_columns": [ ? ? ? ?"id", ? ? ? ?"rank1", ? ? ? ?"rank2", ? ? ? ?"log_time", ? ? ? ?"prefix_uid", ? ? ? ?"desc1", ? ? ? ?"rank3" ? ? ?], ? ? ?"attached_condition": "((`ytt`.`t1`.`rank3` = 100) and (`ytt`.`t1`.`rank2` = 100) and (`ytt`.`t1`.`rank1` = 100))" ? ?} ?}}1 row in set, 1 warning (0.00 sec)
對比下以上兩個,加了HINT的比不加HINT的cost小了100倍。
總結(jié)下,就是說表的cardinality值影響這張的查詢計劃,如果這個值沒有正常更新的話,就需要手工加HINT了。相信MySQL未來的版本會帶來更多的HINT。
哎!你這問題簡單也相當(dāng)不簡單。
這個是數(shù)據(jù)庫實時問題,也算是技術(shù)難度很高的話題。本不想回答的。但是又問到了我。
原因很簡單,本來就是一個答題系統(tǒng),卻要用監(jiān)控系統(tǒng)的實時性,從成本上說,你認(rèn)為合適么?
如果數(shù)據(jù)極為重要還要配置UPS。實時系統(tǒng)的成本很高。
第一:你可以考慮一下mysql 內(nèi)存表,這個在多連接中是共享的,創(chuàng)建也很簡單。但是畢竟mysql不是實時數(shù)據(jù)庫,大并發(fā)內(nèi)存表也一樣死鎖。斷電數(shù)據(jù)就消失,還要考慮保存問題。
第二:你可以考慮自己創(chuàng)建緩沖層代碼,先更新緩沖層,然后寫入數(shù)據(jù)庫。只是一個變通問題。
然后每次訪問緩沖層即可。
如果是ASP.NET,你可以使用感知緩存功能開發(fā),比java容易的多。
目前對實時要求高的,基本是內(nèi)存數(shù)據(jù)庫,嵌入式數(shù)據(jù)庫等??隙ú荒馨褧r間浪費在IO傳輸上。