轉載請註明出處:http://blog.csdn.net/l1028386804/article/details/46794245
一、優化簡單介紹html
mysql優化是多方面的。原則是下降系統的瓶頸,下降資源的佔用。添加系統的反應速度。mysql
好比,經過優化文件系統。提升磁盤I/O的讀寫速度;經過優化操做系統調度策略,提升mysql在高負荷狀況下的負載能力。優化表結構、索引、查詢語句等使查詢響應更快在mysql中,可以使用show status語句查詢一些mysql的性能參數sql
show status like 'value';
當中value是要查詢的參數值,一些常用性能參數例如如下:數據庫
connections:鏈接mysqlserver的次數緩存
uptime:mysqlserver的上線時間網絡
slow_queries:慢查詢的次數mysql優化
com_select:查詢操做次數多線程
com_insert:插入操做次數併發
com_update:更新操做次數數據庫設計
com_delete:刪除操做次數
假設查詢mysqlserver的鏈接次數,可以運行例如如下語句
show status like 'connections';
假設查詢mysqlserver的慢查詢次數。可以運行例如如下語句
show status like 'slow_queries';
二、優化查詢
查詢是數據庫最頻繁的操做。提升查詢速度可以有效地提升mysql數據庫的性能
(1)分析查詢語句
經過對查詢語句的分析。可以瞭解查詢語句的運行狀況找出查詢語句運行的瓶頸
mysql中提供了EXPLAIN語句和DESCRIBE語句。用來分析查詢語句
EXPLAIN語句的基本的語法
EXPLAIN [EXTENDED] SELECT SELECT_OPTION
使用EXTENDEDkeyword,EXPLAIN語句將產生附加信息。
SELECT_OPTION是SELECT 語句的查詢選項,包含FROM WHERE子句等
運行該語句。能夠分析EXPLAIN後面的select語句的運行狀況。並且能夠分析所查詢的表的一些特徵
使用EXPLAIN語句來分析1個查詢語句
USE TEST; EXPLAIN EXTENDED SELECT * FROM PERSON;
如下對結果進行解釋
· id
SELECT識別符。這是SELECT的查詢序列號。
· select_type
SELECT類型,可以爲下面不論什麼一種:
SIMPLE:簡單SELECT(不使用UNION或子查詢)
PRIMARY:表示主查詢,或者是最外層的查詢語句(多表鏈接的時候)
UNION:表示鏈接查詢的第二個或後面的查詢語句
DEPENDENT UNION:UNION鏈接查詢中的第二個或後面的SELECT語句。取決於外面的查詢
UNION RESULT:UNION鏈接查詢的結果
SUBQUERY:子查詢中的第一個SELECT語句
DEPENDENT SUBQUERY:子查詢中的第一個SELECT語句。取決於外面的查詢
DERIVED:導出表的SELECT(FROM子句的子查詢)
· table
表示查詢的表
· type
表示表的聯接類型
如下給出各類聯接類型,依照從最佳類型到最壞類型進行排序:
(1)system
表僅有一行(=系統表)。這是const聯接類型的一個特例。
(2)const
表最多僅僅有一個匹配行。它將在查詢開始時被讀取。
餘下的查詢優化中被做爲常量對待。const表查詢速度很是快,因爲它們僅僅讀取一次。
const用於常數值比較PRIMARY KEY或UNIQUE索引的所有部分的場合。
在如下的查詢中,tbl_name可以用於const表:
SELECT * from tbl_name WHERE primary_key=1;SELECT * from tbl_name WHERE primary_key_part1=1和 primary_key_part2=2;
(3)eq_ref
對於每個來自於前面的表的行組合。從該表中讀取一行。
這多是最好的聯接類型,除了const類型。
它用在一個索引的所有部分被聯接使用並且索引是UNIQUE或PRIMARY KEY時。
eq_ref可以用於使用「=」 操做符比較的帶索引的列。比較值可以爲常量或一個使用在該表前面所讀取的表的列的表達式。
在如下的樣例中,MySQL可以使用eq_ref聯接來處理ref_tables:
SELECT * FROM ref_table,other_table WHERE ref_table.key_column=other_table.column; SELECT * FROM ref_table,other_table WHERE ref_table.key_column_part1=other_table.column AND ref_table.key_column_part2=1;
(4)ref
對於每個來自於前面的表的隨意行組合。將從該表中讀取所有匹配的行。
假設聯接僅僅使用索引鍵的最左邊的前綴,或假設索引鍵不是UNIQUE或PRIMARY KEY,則使用ref。
假設使用的鍵只匹配少許行,該聯接類型是不錯的。
ref可以用於使用=或<=>操做符的帶索引的列。
在如下的樣例中,MySQL可以使用ref聯接來處理ref_tables:
SELECT * FROM ref_table WHERE key_column=expr; SELECT * FROM ref_table,other_table WHERE ref_table.key_column=other_table.column; SELECT * FROM ref_table,other_table WHERE ref_table.key_column_part1=other_table.column AND ref_table.key_column_part2=1;
(5)ref_or_null
該聯接類型如同ref,但是加入了MySQL可以專門搜索包括NULL值的行。在解決子查詢中經常使用該聯接類型的優化。
在如下的樣例中,MySQL可以使用ref_or_null聯接來處理ref_tables:
SELECT * FROM ref_table WHERE key_column=expr OR key_column IS NULL;
(6) index_merge
該聯接類型表示使用了索引合併優化方法。
在這樣的狀況下,key列包括了所用到的索引的清單。key_len列包括了所用到的索引的最長長度。
(7) unique_subquery
該類型替換了如下形式的IN子查詢的ref:
value IN (SELECT primary_key FROM single_table WHERE some_expr)
unique_subquery是一個索引查找類型,可以全然替換子查詢,效率更高。
(8) index_subquery
該聯接類型相似於unique_subquery,只是索引類型不需要是惟一索引,可以替換IN子查詢,但僅僅適合下列形式的子查詢中的非惟一索引:
value IN (SELECT key_column FROM single_table WHERE some_expr)
(9) range
僅僅檢索給定範圍的行,使用一個索引來檢索行數據。key列顯示使用了哪一個索引,key_len顯示所使用索引的長度。
在該類型中ref列爲NULL。
當使用=、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN或者IN操做符。用常量比較keyword列時,類型爲range。
如下介紹幾種檢索指定行數據的狀況
SELECT * FROM tbl_name WHERE key_column = 10; SELECT * FROM tbl_name WHERE key_column BETWEEN 10 and 20; SELECT * FROM tbl_name WHERE key_column IN (10,20,30); SELECT * FROM tbl_name WHERE key_part1= 10 AND key_part2 IN (10,20,30);
(10) index
該聯接類型與ALL一樣。除了掃描索引樹。其它狀況都比ALL快,因爲索引文件一般比數據文件小。
當查詢僅僅使用做爲單索引一部分的列時,MySQL可以使用該聯接類型。
(11) ALL
對於每個來自於先前的表的行組合,進行完整的表掃描。
假設第一個表沒標記爲const,這樣運行計劃就不會很是好。
一般可以添加不少其它的索引來擺脫ALL。使得行能基於前面的表中的常數值或列值被檢索出。
possible_keys
possible_keys列指出MySQL能供給使用的索引鍵有哪些。
注意,該列全然獨立於EXPLAIN輸出所看到的的表的次序。
這意味着在possible_keys中的某些索引鍵實際上不能按生成的表次序使用。
假設該列是NULL,則沒有相關的索引。在這樣的狀況下,可以經過檢查WHERE子句查看可否夠引用某些列或適合的索引列來提升查詢性能。
假設是這樣。創造一個適當的索引並且再次用EXPLAIN檢查查詢。
假設要查詢一張表有什麼索引,可以使用
SHOW INDEX FROM tbl_name
key
key列顯示MySQL實際決定使用的鍵(索引)。假設沒有選擇索引,那麼可能列的值是NULL。
要想強制MySQL使用或忽略possible_keys列中的索引。在查詢中可以使用
FORCE INDEX -- 強逼使用某個索引 USE INDEX --使用某個索引 IGNORE INDEX -- 忽略某個索引
對於MyISAM引擎和BDB引擎的表,執行 ANALYZE TABLE 可以幫助優化器選擇更好的索引。
對於MyISAM表。可以使用myisamchk --analyze。
key_len
key_len列顯示MySQL決定使用的索引鍵的長度(按字節計算)。
假設鍵是NULL。則長度爲NULL。
注意經過key_len值咱們可以肯定MySQL將實際使用一個多索引鍵索引的幾個字段。
ref
ref列顯示使用哪一個列或常數與索引一塊兒查詢記錄。
rows
rows列顯示MySQL預估運行查詢時必須要檢索的行數。
Extra
該列包括MySQL處理查詢時的具體信息。
如下解釋了該列可以顯示的不一樣的文本字符串:
Distinct
MySQL發現第1個匹配行後,中止爲當前的行組合搜索不少其它的行。
Not exists
MySQL能夠對查詢進行LEFT JOIN優化,發現1個匹配LEFT JOIN標準的行後,再也不爲前面的的行組合在該表內檢查不少其它的行。
如下是一個可以這樣優化的查詢類型的樣例:
SELECT * FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL;
假定t2.id定義爲NOT NULL。
在這樣的狀況下。MySQL使用t1.id的值掃描t1並查找t2中的行。
假設MySQL在t2中發現一個匹配的行。它知道t2.id毫不會爲NULL,並且再也不掃描t2內有一樣的id值的行。換句話說,對於t1的每個行,MySQL僅僅需要在t2中查找一次,無論t2內實際有多少匹配的行。
range checked for each record (index map: #)
MySQL沒有發現好的可以使用的索引。但發現假設來自前面的表的列值已知,可能部分索引可以使用。
對前面的表的每個行組合,MySQL檢查可否夠使用range或index_merge訪問方法來獲取行。
這並不很是快,但比運行沒有索引的聯接要快得多。
可以參考一下這篇文章:一個用戶SQL慢查詢分析,緣由及優化
裏面就提到了range checked for each record
Using filesort
MySQL需要額外的一次傳遞,以找出怎樣按排序順序檢索行。
經過依據聯接類型瀏覽所有行併爲所有匹配WHERE子句的行保存排序keyword和行的指針來完畢排序。
而後keyword被排序。並按排序順序檢索行
假設是order by操做就會用到這個Using filesort,固然filesort不是指使用文件來排序,你們不要誤會了。。。
Using index
從僅僅使用索引樹中的信息而不需要進一步搜索讀取實際的行來檢索表中的列信息。
當查詢僅僅使用做爲單一索引一部分的列時,可以使用該策略。
Using temporary
爲了解決查詢,MySQL需要建立一個暫時表來容納結果。
典型狀況如查詢包括可以按不一樣狀況列出列的GROUP BY和ORDER BY子句時。
通常用到暫時表都會看到 Using temporary
Using where
WHERE子句用於限制哪個行匹配下一個表或發送到client。
除非你專門從表中索取或檢查所有行。假設Extra值不爲Using where並且表聯接類型爲ALL或index,查詢可能會有一些錯誤。
Using index for group-by
相似於訪問表的Using index方式,Using index for group-by表示MySQL發現了一個索引。可以用來查詢GROUP BY或DISTINCT查詢的所有列。而不要額外搜索硬盤訪問實際的表。
並且,按最有效的方式使用索引。以便對於每個組,僅僅讀取少許索引條目。
DESCIBE語句的用法與EXPLAIN語句是同樣的。並且分享結果也是同樣的DESCIBE語句的語法例如如下
DESCRIBE SELECT select_options
DESCIBE可以縮寫成DESC
(2)索引對查詢速度的影響
mysql中提升性能的一個最有效的方式就是對數據表設計合理的索引。索引提供了高效訪問數據的方法。並且加快查詢速度。所以索引對查詢速度有着相當重要的影響。
假設查詢沒有索引,查詢語句將掃描表中所有記錄。在數據量大的狀況下,這樣查詢的速度會很是慢。假設使用索引進行查詢,查詢語句可以依據索引高速定位到待查詢記錄。從而下降查詢的記錄數,達到提升查詢速度的目的。
如下是查詢語句中不使用索引和使用索引的對照,首先分析未使用索引的查詢狀況,EXPLAIN語句運行例如如下
EXPLAIN SELECT `ID`,`name` FROM `test`.`emp` WHERE `name` ='nihao'
可以看到。rows列的值是3說「SELECT `ID`,`name` FROM `test`.`emp` WHERE `name` ='nihao'」 語句掃描了表中的3條記錄
而後在emp表加上索引
CREATE INDEX ix_emp_name ON emp(name)
現在再分析上面的查詢語句,運行的EXPLAIN語句結果例如如下
結果顯示,rows列的值爲1。這表示這個查詢語句僅僅掃描了表中的一條記錄,其它查詢速度天然比掃描3條記錄快。而且possible_keys 和key的值都是ix_emp_name 。這說明查詢時使用了ix_emp_name 索引。假設表中記錄有100條、1000條、10000條優點就顯現出來了
(3)使用索引查詢
索引可以提升查詢速度,但並不是使用帶有索引的字段查詢時,索引都會起做用。
如下的幾種狀況跟跟SQLSERVER同樣,有可能用不到索引
(1)使用likekeyword的查詢語句
使用likekeyword進行查詢的時候,假設匹配字符串的第一個字符爲「%」。索引不起做用。僅僅有「%」不在第一個位置,索引纔會起做用
使用likekeyword,並且匹配字符串中含有「%」字符,EXPLAIN語句例如如下
USE test; EXPLAIN SELECT * FROM `test`.`emp` WHERE `name` LIKE '%x';
USE test; EXPLAIN SELECT * FROM `test`.`emp` WHERE `name` LIKE 'x%';
name上有索引ix_emp_name
第一個查詢type爲ALL,表示要全表掃描
第二個查詢TYPE爲index。表示會掃描索引
like keyword可否利用上索引跟SQLSERVER是同樣的
我以前寫過一篇文章:like語句百分號前置會使用到索引嗎?
(2)使用多列索引的查詢語句
mysql可以爲多個字段建立索引。一個索引可以包含16個字段(跟SQLSERVER同樣)對於多列索引,僅僅有查詢條件中使用了
這些字段中的第一個字段時,索引纔會被使用。這個字段叫:前導索引或前導列
在表person中name,age字段建立多列索引,驗證多列索引的狀況
CREATE INDEX ix_person_name_age ON `person` (name,age) EXPLAIN SELECT ID,Name,Age,job FROM `person` WHERE `Name` ='suse'
EXPLAIN SELECT ID,Name,Age,job FROM `person` WHERE `age` =12
從第一條查詢看出,WHERE `Name` ='suse'的記錄有一條。掃描了一條記錄並且使用了ix_person_name_age 索引
從第二條記錄可以看出,rows列的值爲4,說明共掃描了4條記錄。並且key列值爲NULL,說明EXPLAIN SELECT ID,Name,Age,job FROM `person` WHERE `age` =12
語句並無使用索引。因爲age字段是多列索引的第二個字段。僅僅有查詢條件中使用了name字段纔會使用ix_person_name_age 索引
這個跟SQLSERVER是同樣的。具體請看:SQLSERVER彙集索引與非彙集索引的再次研究(下)
(3)使用ORkeyword的查詢語句
查詢語句的查詢條件中僅僅有ORkeyword,而且OR先後的兩個條件中的列都是索引時,查詢中才使用索引,不然,查詢不使用索引
查詢語句使用ORkeyword的狀況
咱們再建立一個索引
CREATE INDEX ix_person_age ON `person` (age) EXPLAIN SELECT Name,Age FROM `person` WHERE `Name` ='SUSE' OR `job`='SPORTMAN'
EXPLAIN SELECT Name,Age FROM `person` WHERE `AGE` =2 OR `Name` ='SUSE'
你們要注意。這裏跟剛纔不同,此次咱們select的字段僅僅有name和age。而不是select出全部字段
因爲並無在job這個字段上創建索引,因此第一個查詢使用的是全表掃描
第二個查詢因爲name字段和age字段都有索引,那麼mysql可以利用這兩個索引的當中之中的一個,這裏是ix_person_name_age索引來查找記錄。利用索引來查找記錄會快很是多
(4)優化子查詢
mysql從4.1版本號開始支持子查詢。使用子查詢可以進行SELECT語句的嵌套查詢,即一個SELECT查詢的結果做爲還有一個SELECT語句的條件
子查詢可以一次性完畢很是多邏輯需要多個步驟才幹完畢的SQL操做。子查詢儘管使查詢語句靈活。但是運行效率不高。
運行子查詢時,mysql需要爲內層查詢語句結果創建一個暫時表。而後外層查詢語句從暫時表中查詢記錄
查詢完成後,再撤銷暫時表。
所以。子查詢的速度會受到必定影響。假設查詢的數據量特別大,這樣的影響就會更大。
在mysql中。可以使用鏈接(join)查詢來取代子查詢。
鏈接查詢不需要創建暫時表,其速度比子查詢快,假設查詢中使用索引的話,性能會更好。
因此很是多網上的文章都說盡可能使用join來取代子查詢,儘管網上也說mysql5.7對於子查詢有很是大的改進,但是假設不是使用mysql5.7仍是需要注意的
假設系統中join語句特別多還需要注意改動my.ini或my.cnf文件裏的join_buffer_size大小。預防性能問題
優化數據庫結構
一個好的數據庫設計方案對於數據庫的性能常常起到事半功倍的效果。
數據庫結構的設計需要考慮數據冗餘、查詢和更新速度、字段的數據類型是否合理等多方面
(1)將字段很是多的表拆分紅多個表
有時候有些字段使用頻率很是低或者字段的數據類型比較大,那麼可以考慮垂直拆分的方法,把不常用的字段和大字段拆分出去
(2)添加中間表
對於需要經常聯合查詢的表,可以創建中間表以提升查詢效率。經過創建中間表,把需要經常聯合查詢的數據插入到中間表中,而後將原來的聯合查詢改成對中間表的查詢。以此來提升查詢效率。
(3)添加冗餘字段
設計數據庫表時應儘可能遵循範式理論,儘量下降冗餘字段,但是現今存儲硬件愈來愈廉價,有時候查詢數據的時候需要join多個表。這樣在高峯期間會影響查詢的效率。咱們需要反範式而爲之。添加一些必要的冗餘字段,以空間換時間需要這樣作會添加開發的工做量和維護量。但是假設能換來可觀的性能提高,這樣作也是值得的
(4)優化插入記錄的速度
插入記錄時,影響插入速度的主要是索引、惟一性校驗、一次插入記錄條數等。
依據實際狀況,可以分別進行優化
對於myisam表。常見優化方法例如如下:
一、禁用索引
對於非空表,插入記錄時,mysql會依據表的索引對插入的記錄創建索引。假設插入大量數據,創建索引會減小插入記錄的速度。
爲了解決問題,可以在插入記錄以前禁用索引。數據插入完成後再開啓索引
禁用索引語句例如如下:
ALTER TABLE table_name DISABLE KEYS ;
當中table_name是禁用索引的表的表名
又一次開啓索引語句例如如下:
ALTER TABLE table_name ENABLE KEYS ;
對於空表批量導入數據,則不需要進行此操做,因爲myisam表是在導入數據以後才創建索引。
二、禁用惟一性檢查
插入數據時,mysql會對插入的記錄進行惟一性校驗。這樣的惟一性校驗也會減小插入記錄的速度。
爲了減小這樣的狀況對查詢速度的影響,可以在插入記錄以前禁用惟一性檢查,等到記錄插入完成以後再開啓
禁用惟一性檢查的語句例如如下:
SET UNIQUE_CHECKS=0;
開啓惟一性檢查的語句例如如下:
SET UNIQUE_CHECKS=1;三、使用批量插入
插入多條記錄時,可以使用一條INSERT語句插入一條記錄,也可以使用一條INSERT語句插入多條記錄。
第一種狀況
INSERT INTO emp(id,name) VALUES (1,'suse'); INSERT INTO emp(id,name) VALUES (2,'lily'); INSERT INTO emp(id,name) VALUES (3,'tom');
另一種狀況
INSERT INTO emp(id,name) VALUES (1,'suse'),(2,'lily'),(3,'tom')
另一種狀況要比第一種狀況要快
四、使用LOAD DATA INFILE批量導入
當需要批量導入數據時。假設能用LOAD DATA INFILE語句,就儘可能使用。因爲LOAD DATA INFILE語句導入數據的速度比INSERT語句快很是多
對於INNODB引擎的表,常見的優化方法例如如下:
一、禁用惟一性檢查
插入數據時。mysql會對插入的記錄進行惟一性校驗。
這樣的惟一性校驗也會減小插入記錄的速度。
爲了減小這樣的狀況對查詢速度的影響,可以在插入記錄以前禁用惟一性檢查,等到記錄插入完成以後再開啓
禁用惟一性檢查的語句例如如下:
SET UNIQUE_CHECKS=0;
開啓惟一性檢查的語句例如如下:
SET UNIQUE_CHECKS=1;
二、禁用外鍵約束
插入數據以前運行禁止對外鍵的檢查,數據插入完畢以後再恢復對外鍵的檢查。禁用外鍵檢查的語句例如如下:
SET FOREIGN_KEY_CHECKS=0;
恢復對外鍵的檢查語句例如如下
SET FOREIGN_KEY_CHECKS=1;
三、禁止本身主動提交
插入數據以前禁止事務的本身主動提交,數據導入完畢以後。運行恢復本身主動提交操做或顯式指定事務
USE test; START TRANSACTION; INSERT INTO emp(name) VALUES('ming'); INSERT INTO emp(name) VALUES('lily'); commit;
(5)分析表、檢查表、優化表、修復表和CHECKSUM表
mysql提供了分析表、檢查表和優化表的語句
分析表主要是分析keyword的分佈。
檢查表主要是檢查表是否存在錯誤;
優化表主要是消除刪除或者更新形成的空間浪費
修復表主要對myisam表文件進行修復
CHECKSUM表主要對錶傳輸數據前和傳輸後進行比較
一、分析表
mysql中提供了ANALYZE TABLE 語句分析表。ANALYZE TABLE 語句的基本的語法例如如下
ANALYZE [LOCAL|NO_WRITE_TO_BINLOG] TABLE TBL_NAME [,TBL_NAME]...
LOCALkeyword是NO_WRITE_TO_BINLOGkeyword的別名,兩者都是運行過程不寫入二進制日誌,tbl_name爲分析的表的表名可以有一個或多個
使用ANALYZE TABLE 分析表的過程當中,數據庫系統會本身主動對錶加一個僅僅讀鎖。在分享期間,僅僅能讀取表的記錄。不能更新和插入記錄
ANALYZE TABLE 語句能分析INNODB、BDB和MYISAM類型的表
使用ANALYZE TABLE 來分析emp表,運行語句例如如下:
ANALYZE TABLE emp;
上面結果顯示說明
table:表示分析的表名
op:表示運行的操做。analyze表示進行分析操做
msg_type:表示信息類型其值通常是狀態(status)、信息(info)、注意(note)、警告(warning)和錯誤(error)之中的一個
msg_text:顯示信息
實際上分析表跟SQLSERVER裏的更新統計信息是幾乎相同的
主要就是爲了索引的基數更加準確。從而使查詢優化器能夠更加準確的預估行數
emp表的記錄行數是18
分析表以後。Cardinality 基數更加準確了
二、檢查表
mysql中使用check table語句來檢查表。check table語句能夠檢查innodb和myisam類型的表是否存在錯誤。
對於myisam類型的表,check table語句還會更新keyword統計數據。
而且,check table也可以檢查視圖是否有錯誤,
比方在視圖定義中被引用的表已不存在。
該語句基本的語法例如如下:
CHECK TABLE TBL_NAME [,tbl_name]...[option]... option={QUICK|FAST|MEDIUM|EXTENDED|CHANGED}
當中。tbl_name是表名。option參數有5個取值各自是QUICK、FAST、MEDIUM、EXTENDED、CHANGED
各個選項的意思各自是
QUICK:不掃描行。不檢查錯誤的鏈接
FAST:僅僅檢查沒有被正確關閉的表
MEDIUM:掃描行。以驗證被刪除的鏈接是有效的,也可以計算各行的keyword校驗和,並使用計算出的校驗和驗證這一點
EXTENDED:對每行的所有keyword進行一個全面的keyword查找。這可以確保表是100%一致的,但是花的時間較長
CHANGED:僅僅檢查上次檢查後被更改的表和沒有被正確關閉的表
option僅僅對myisam表有效。對innodb表無效。
check table語句在運行過程當中也會給表加上僅僅讀鎖。
三、優化表
mysql中使用OPTIMIZE TABLE語句來優化表。該語句對INNODB和MYISAM表都有效。但是,OPTIMIZE TABLE語句僅僅能優化表中的
VARCHAR、BLOB、TEXT類型的字段
OPTIMIZE TABLE語句的基本的語法例如如下:
OPTIMIZE [LOCAL|NO_WRITE_TO_BINLOG] TABLE TBL_NAME [,TBL_NAME]...
LOCAL和NO_WRITE_TO_BINLOGkeyword的意義和分析表一樣,都是指定不寫入二進制日誌
tbl_name是表名
經過OPTIMIZE TABLE語句可以消除刪除和更新形成的文件碎片。
OPTIMIZE TABLE語句在運行過程當中也會給表加上僅僅讀鎖。
提示:一個表使用了TEXT或者BLOB這種數據類型,假設已經刪除了表的一大部分,或者已經對含有可變長度行的表(含有VARCHAR、BLOB或TEXT列的表)進行了很是多更新。則應使用OPTIMIZE TABLE來又一次利用未使用的空間。並整理數據文件的碎片。在多數設置中,根本不需要執行OPTIMIZE TABLE。即便對可變長度的行進行了大量更新,也不需要經常執行。每週一次或每個月一次就能夠,並且僅僅需要對特定表進行OPTIMIZE TABLE OPTIMIZE TABLE語句相似於SQLSERVER的重建索引和收縮數據文件的功能
四、修復表
mysql中使用Repair Table來修復myisam表,僅僅對MyISAM和ARCHIVE類型的表有效。
REPAIR [LOCAL|NO_WRITE_TO_BINLOG] TABLE TBL_NAME [,tbl_name]...[option]... option={QUICK|EXTENDED|USE_FRM}
選項的意思各自是:
QUICK:最快的選項,僅僅修復索引樹。
EXTENDED:最慢的選項,需要逐行重建索引。
USE_FRM:僅僅有當MYI文件丟失時才使用這個選項。全面重建整個索引。
與Analyze Table同樣,Repair Table也可以使用local來取消寫入binlog。
五、Checksum 表
數據在傳輸時,可能會發生變化,也有可能因爲其餘緣由損壞,爲了保證數據的一致。咱們可以計算checksum(校驗值)。
使用MyISAM引擎的表會把checksum存儲起來,稱爲live checksum,當數據發生變化時,checksum會對應變化。
語法例如如下:
CHECKSUM TABLE tbl_name [, tbl_name] ... [ QUICK | EXTENDED ]
quick:表示返回存儲的checksum值
extended:表示又一次計算checksum
假設沒有指定選項,則默認使用extended。
Checksum 表主要用來對照在傳輸表數據以前和表數據以後。表的數據是否發生了變化,好比插入了數據或者刪除了數據,或者有數據損壞
CHECKSUM值都會改變。
優化MYSQLserver
水電費優化mysqlserver主要從兩個方面入手,一方面是對硬件進行優化;還有一方面是對mysqlserver的參數進行優化
一、優化server硬件
server的硬件性能直接決定着MYSQL數據庫的性能。
硬件的性能瓶頸直接決定MYSQL數據庫的執行速度和效率。
優化server硬件的幾種方法
(1)配置較大的內存。
足夠大的內存,是提升mysql數據庫性能之中的一個。
內存速度比磁盤I/O快得多,可以經過添加系統緩衝區容量。使數據庫
在內存停留時間更長,以下降磁盤I/O
(2)配置快速磁盤系統。以下降讀盤等待時間,提升響應速度
(3)合理分佈磁盤I/O,把磁盤I/O分散在多個設備上,以下降資源競爭,提升並行操做能力
(4)配置多處理器。mysql是多線程的數據庫,多處理器可同一時候運行多個線程
二、優化MYSQL的參數
經過優化MYSQL的參數可以提升資源利用率。從而達到提升MYSQLserver的性能的目的。
MYSQLserver的配置參數都在my.cnf或者my.ini文件的[mysqld]組中。
如下對幾個對性能影響較大的參數進行介紹
咱們先看一下與網絡鏈接的性能配置項及對性能的影響。 ● max_conecctions:整個 MySQL 贊成的最大鏈接數。 這個參數主要影響的是整個 MySQL 應用的併發處理能力,當系統中實際需要的鏈接量大於 max_conecctions 的狀況下,因爲 MySQL 的設置限制,那麼應用中一定會產生鏈接請求的等待, 從而限制了相應的併發量。因此通常來講,僅僅要 MySQL 主機性能贊成,都是將該參數設置的盡 可能大一點。通常來講 500 到 800 左右是一個比較合適的參考值 ● max_user_connections:每個用戶贊成的最大鏈接數; 上面的參數是限制了整個 MySQL 的鏈接數。而 max_user_connections 則是針對於單個用戶的連 接限制。在普通狀況下咱們可能都較少使用這個限制。僅僅有在一些專門提供 MySQL 數據存儲服 務,或者是提供虛擬主機服務的應用中可能需要用到。除了限制的對象差異以外,其它方面和 max_connections 同樣。
這個參數的設置全然依賴於應用程序的鏈接用戶數,對於普通的應用來 說,全然沒有作太多的限制,可以儘可能放開一些。 ● net_buffer_length:網絡包傳輸中。傳輸消息以前的 net buffer 初始化大小。 這個參數主要可能影響的是網絡傳輸的效率,因爲該參數所設置的僅僅是消息緩衝區的初始化大 小。因此形成的影響主要是當咱們的每次消息都很是大的時候 MySQL 老是需要屢次申請擴展該緩 衝區大小。
系統默認大小爲 16KB。通常來講可以知足大多數場景。固然假設咱們的查詢都是非 常小。每次網絡傳輸量都很是少。而且系統內存又比較緊缺的狀況下。也可以適當將該值下降到 8KB。 ● max_allowed_packet:在網絡傳輸中,一次傳消息輸量的最大值; 這個參數與 net_buffer_length 相相應,僅僅只是是 net buffer 的最大值。當咱們的消息傳輸量 大於 net_buffer_length 的設置時。MySQL 會本身主動增大 net buffer 的大小。直到緩衝區大小達 到 max_allowed_packet 所設置的值。系統默認值爲 1MB,最大值是 1GB,必須設定爲 1024 的倍 數。單位爲字節。 ● back_log:在 MySQL 的鏈接請求等待隊列中贊成存放的最大鏈接請求數。
鏈接請求等待隊列,其實是指當某一時刻client的鏈接請求數量過大的時候,MySQL 主線程沒 辦法及時給每個新的鏈接請求分配(或者建立)鏈接線程的時候,尚未分配到鏈接線程的 所有請求將存放在一個等待隊列中。這個隊列就是 MySQL 的鏈接請求隊列。當咱們的系統存在 瞬時的大量鏈接請求的時候,則應該注意 back_log 參數的設置。
系統默認值爲 50,最大可以設 置爲 65535。當咱們增大 back_log 的設置的時候。同一時候還需要主義 OS 級別對網絡監聽隊列的限 制,因爲假設 OS 的網絡監聽設置小於 MySQL 的 back_log 設置的時候,咱們加大「back_log」設 置是沒有意義的。 上面介紹了網絡鏈接交互相關的主要優化設置,如下咱們再來看看與每個client鏈接想相應的連 接線程。 在 MySQL 中。爲了儘可提升client請求建立鏈接這個過程的性能,實現了一個 Thread Cache 池,將 空暇的鏈接線程存放在當中。而不是完畢請求後就銷燬。這樣,當有新的鏈接請求的時候,MySQL 首先會 檢查 Thread Cache 池中是否存在空暇鏈接線程,假設存在則取出來直接使用,假設沒有空暇鏈接線程。 才建立新的鏈接線程。
在 MySQL 中與鏈接線程相關的系統參數及狀態變量說明例如如下: ● thread_cache_size:Thread Cache 池中應該存放的鏈接線程數。 當系統最初啓動的時候,並不會當即就建立 thread_cache_size 所設置數目的鏈接線程存放在 Thread Cache 池中,而是隨着鏈接線程的建立及使用,慢慢的將用完的鏈接線程存入當中。當 存放的鏈接線程達到 thread_cache_size 值以後。MySQL 就不會再續保存用完的鏈接線程了。
假設咱們的應用程序使用的短鏈接。Thread Cache 池的功效是最明顯的。因爲在短鏈接的數據 庫應用中,數據庫鏈接的建立和銷燬是很是頻繁的。假設每次都需要讓 MySQL 新建和銷燬相應 的鏈接線程,那麼這個資源消耗其實是很是大的,而當咱們使用了 Thread Cache 以後。因爲 鏈接線程大部分都是在建立好了等待取用的狀態,既不需要每次都又一次建立。又不需要在使用 完 之 後 銷 毀 , 所 以 可 以 節 省 下 大 量 的 系 統 資 源 。 所 以 在 短 連 接 的 應 用 系 統 中 , thread_cache_size 的值應該設置的相對大一些。不該該小於應用系統對數據庫的實際併發請求 數。 而假設咱們使用的是長鏈接的時候,Thread Cache 的功效可能並無使用短鏈接那樣的大。但 也並不是全然沒有價值。
因爲應用程序即便是使用了長鏈接,也很是難保證他們所管理的所有連 接都能處於很是穩定的狀態,仍然會有很多鏈接關閉和新建的操做出現。在有些併發量較高。應 用server數量較大的系統中,每分鐘十來次的鏈接建立與關閉的操做是非常常見的。而且假設應 用server的鏈接池管理不是太好,easy產生鏈接池抖動的話。所產生的鏈接建立和銷燬操做將 會不少其它。
因此即便是在使用長鏈接的應用環境中,Thread Cache 機制的利用仍然是對性能大有 幫助的。僅僅只是在長鏈接的環境中咱們不需要將 thread_cache_size 參數設置太大,通常來講 可能 50 到 100 之間應該就可以了。 ● thread_stack:每個鏈接線程被建立的時候,MySQL 給他分配的內存大小。 當 MySQL 建立一個新的鏈接線程的時候,是需要給他分配必定大小的內存堆棧空間,以便存放 client的請求 Query 以及自身的各類狀態和處理信息。只是通常來講假設不是對 MySQL 的鏈接線 程處理機制十分熟悉的話,不該該輕易調整該參數的大小,使用系統的默認值(192KB)基本上 可以所有的普通應用環境。假設該值設置過小。會影響 MySQL 鏈接線程可以處理client請求的 Query 內容的大小,以及用戶建立的 Procedures 和 Functions 等 計算出系統新建鏈接鏈接的 Thread Cache 命中率。也就是經過 Thread Cache 池中取得鏈接線程的次數與系統接收的總鏈接次數的比率,如 下: Threads_Cache_Hit = (Connections - Threads_created) / Connections * 100% 咱們可以經過上面的這個運算公式計算一下上面環境中的 Thread Cache 命中率:Thread_Cache_Hit = (127 - 12) / 127 * 100% = 90.55% 通常來講,當系統穩定運行一段時間以後,咱們的 Thread Cache 命中率應該保持在 90%左右甚至更 高的比率纔算正常。可以看出上面環境中的 Thread Cache 命中比率基本還算是正常的。 Table Cache 相關的優化 咱們先來看一下 MySQL 打開表的相關機制。因爲多線程的實現機制。爲了儘量的提升性能,在 MySQL 中每個線程都是獨立的打開本身需要的表的文件描寫敘述符,而不是經過共享已經打開的表的文件描寫敘述 符的機制來實現。固然。針對於不一樣的存儲引擎可能有不一樣的處理方式。如 MyISAM 表,每個client線 程打開不論什麼一個 MyISAM 表的數據文件都需要打開一個文件描寫敘述符。但假設是索引文件。則可以多個線程 共享同一個索引文件的描寫敘述符。對於 Innodb 的存儲引擎,假設咱們使用的是共享表空間來存儲數據,那 麼咱們需要打開的文件描寫敘述符就比較少,而假設咱們使用的是獨享表空間方式來存儲數據,則相同。由 於存儲表數據的數據文件較多,則相同會打開很是多的表文件描寫敘述符。
除了數據庫的實際表或者索引打開 之外。暫時文件相同也需要使用文件描寫敘述符,相同會佔用系統中 open_files_limit 的設置限額。
爲了解決打開表文件描寫敘述符太過頻繁的問題,MySQL 在系統中實現了一個 Table Cache 的機制,和前 面介紹的 Thread Cache 機制有點相似,主要就是 Cache 打開的所有表文件的描寫敘述符。當有新的請求的時 候不需要再又一次打開,使用結束的時候也不用當即關閉。經過這種方式來下降因爲頻繁打開關閉文件 描寫敘述符所帶來的資源消耗。咱們先看一看 Table Cache 相關的系統參數及狀態變量。 在 MySQL 中咱們經過 table_cache(從 MySQL5.1.3 開始改成 table_open_cache),來設置系統中爲 咱們 Cache 的打開表文件描寫敘述符的數量。
經過 MySQL 官方手冊中的介紹,咱們設置 table_cache 大小的時 候應該經過 max_connections 參數計算得來,公式例如如下: table_cache = max_connections * N; 當中 N 表明單個 Query 語句中所包括的最多 Table 的數量。但是我我的理解這種計算事實上並不是太 準確。分析例如如下: 首先,max_connections 是系統同一時候可以接受的最大鏈接數。但是這些鏈接並不必定都是 active 狀 態的,也就是說可能裏面有很多鏈接都是處於 Sleep 狀態。而處於 Sleep 狀態的鏈接是不可能打開不論什麼 Table 的。 其次,這個 N 爲運行 Query 中包括最多的 Table 的 Query 所包括的 Table 的個數也並不是太合適,因 爲咱們不能忽略索引文件的打開。儘管索引文件在各個鏈接線程之間是可以共享打開的鏈接描寫敘述符的, 但總仍是需要的。而且。假設我 Query 中的每個表的訪問都是經過現經過索引定位檢索的,甚至可能還 是經過多個索引。那麼該 Query 的運行所需要打開的文件描寫敘述符就不少其它了,多是 N 的兩倍甚至三倍。 最後,這個計算的公式僅僅能計算出咱們同一時刻需要打開的描寫敘述符的最大數量,而 table_cache 的 設置也不必定非得依據這個極限值來設定,因爲 table_cache 所設定的僅僅是 Cache 打開的描寫敘述符的數量的 大小,而不是最多可以打開的量的大小。 join_buffer_size :當咱們的 Join 是 ALL 。 index , rang 或者 index_merge 的時候使用的 Buffer; 實際上這種 Join 被稱爲 Full Join。實際上參與 Join 的每個表都需要一個 Join Buffer,因此在 Join 出現的時候,至少是兩個。Join Buffer 的設置在 MySQL 5.1.23 版本號以前最大爲 4GB,但是從 5.1.23 版本號開始,在除了 Windows 以外的 64 位的平臺上可以超出 4BG 的限制。系統默認是 128KB。
● sort_buffer_size:系統中對數據進行排序的時候使用的 Buffer; Sort Buffer 相同是針對單個 Thread 的,因此當多個 Thread 同一時候進行排序的時候。系統中就會出現 多個 Sort Buffer。通常咱們可以經過增大 Sort Buffer 的大小來提升 ORDER BY 或者是 GROUP BY 的處理性能。系統默認大小爲 2MB。最大限制和 Join Buffer 同樣。在 MySQL 5.1.23 版本號以前最大 爲 4GB,從 5.1.23 版本號開始,在除了 Windows 以外的 64 位的平臺上可以超出 4GB 的限制。 假設應用系統中很是少有 Join 語句出現,則可以不用太在意 join_buffer_size 參數的大小設置,但是 假設 Join 語句不是很是少的話,我的建議可以適當增大 join_buffer_size 的設置到 1MB 左右,假設內存充 足甚至可以設置爲 2MB。對於 sort_buffer_size 參數來講,通常設置爲 2MB 到 4MB 之間可以知足大多數 應用的需求。固然。假設應用系統中的排序都比較大,內存充足且併發量不是特別的大的時候,也可以 繼續增大 sort_buffer_size 的設置。
在這兩個 Buffer 設置的時候,最需要注意的就是不要忘記是每個 Thread 都會建立本身獨立的 Buffer,而不是整個系統共享的 Buffer,不要因爲設置過大而形成系統內存 不足。
配置完參數以後,需要從新啓動MYSQL服務才幹生效
怎樣使用查詢緩衝區
查詢緩衝區可以提升查詢的速度。但是這樣的方式僅僅適合查詢語句多、更新較少的狀況。默認狀況下查詢緩衝區的大小爲0,也就是不可用
可以改動query_cache_size以調整查詢緩衝區大小。改動 query_cache_type以調整查詢緩衝區的類型。
在my.ini中改動query_cache_size和query_cache_type的值例如如下所看到的
[mysqld] query_cache_size=512M query_cache_type=1
query_cache_type=1表示開啓查詢緩衝區。僅僅有在查詢語句中包括SQL_NO_CACHEkeyword時,纔不會使用查詢緩衝區。
可以使用FLUSH QUERY CACHE語句來刷新緩衝區,清理查詢緩衝區中的碎片
注意:開啓查詢緩衝區是有風險的,假設命中率不高,或者更新改動語句較多,都會使查詢緩衝區失效,從而使命中率更加低
建議使用memcached等軟件來作二級緩存,除非系統中改動語句較少,命中率較高,這樣纔會看到明顯的性能提高