MySQL 優(yōu)化參數 (my.ini文件中修改)
1. max_connections
最大連接數护奈,默認為100缔莲。連接數越大,占用內存越多霉旗,因為MySQL會為每個連接提供緩沖區(qū)痴奏。
// 最大連接數
show variables like 'max_connections'
// 最大響應連接數
show status like 'max_used_connections'
理想狀況:max_used_connections
/ max_connections
= 85%
2. back_log
如果當前連接數達到了max_connections
,新來的請求將會被存放在堆棧中厌秒,等待資源读拆。
該堆棧的容量即為 back_log
,若新來的請求超過了back_log
鸵闪,將不會被授予連接資源檐晕。
3. interactive_timeout
一個交互連接在被服務器關閉前等待的秒數。
默認值為28800蚌讼,可修改為7200辟灰。
4. key_buffer_size
索引緩沖區(qū)大小,決定了索引處理的速度篡石,即空間換時間芥喇。
只針對 MyISAM 表起作用。
默認值為8M凰萨,可優(yōu)化為256M继控。
// 索引緩沖區(qū)大小
show variables like 'key_buffer_size'
// 有多少個索引讀取請求
show global status like 'key_read_request'
// 有多少個索引讀取請求沒有在內存緩沖區(qū)中找到,需要去磁盤中找
show global status like 'key_reads'
理想狀況:未命中緩沖區(qū)的概率key_reads
/ key_read_request
在1%比較好胖眷。
5. query_cache_size
查詢緩沖區(qū)大小武通,對于同樣的select查詢語句,將直接從緩沖區(qū)中讀取珊搀。
默認為32M厅须。
6. table_cache
表緩沖區(qū)大小。
7. tmp_table_size
臨時表大小食棕,group by操作會用到朗和。
8. 其他的一些buffer設置
- record_buffer_size
- read_rnd_buffer_size
- sort_buffer_size
- join_buffer_size
MySQL 性能優(yōu)化實踐
1. 使用查詢緩存
當有很多相同的查詢被執(zhí)行了多次的時候,這些查詢結果會被放到一個緩存中簿晓。
這樣眶拉,后續(xù)的相同的查詢就不用操作表而直接訪問緩存結果了。
// 查詢緩存不開啟
$r = mysql_query("SELECT * FROM student WHERE signup_date = CURDATE()");
// 開啟查詢緩存
$today = date("Y-m-d");
$r = mysql_query("SELECT * FROM student WHERE signup_date = '$today'");
像 CURDATE()
, NOW()
和 RAND()
或是其它的諸如此類的SQL函數都不會開啟查詢緩存憔儿。
因為這些函數的返回值是不定的忆植。
2. 當只要一行數據時使用 LIMIT 1
MySQL數據庫引擎會在找到一條數據后停止搜索,而不是繼續(xù)往后查少下一條符合記錄的數據谒臼。
// 沒有效率的:
$r = mysql_query("SELECT * FROM user WHERE country = 'China'");
if (mysql_num_rows($r) > 0) {
// ...
}
// 有效率的:
$r = mysql_query("SELECT 1 FROM user WHERE country = 'China' LIMIT 1");
if (mysql_num_rows($r) > 0) {
// ...
}
3. 一些操作:
- 使用Explain來分析Select查詢語句
EXPLAIN SELECT * FROM products WHERE products_id = '123'
如果要清空表朝刊,不要使用 delete,使用 truncate table users
如果要導入大量數據蜈缤,使用 load data infile
經常清理碎片:optimize table users
4. 索引
關于索引拾氓,參見另一篇文章 MySQL 索引學習筆記
5. 存儲引擎
關于存儲引擎,參見另一篇文章 MySQL 存儲引擎學習筆記
6. 靜態(tài) (固定長度) 數據表
關于靜態(tài) (固定長度) 數據表底哥,參見另一篇文章 MySQL 靜態(tài) (固定長度) 數據表 特性
7. 避免 SELECT *
從數據庫里讀出越多的數據咙鞍,那么查詢就會變得越慢。
8. 永遠為每張表設置一個ID
我們應該為數據庫里的每張表都設置一個ID做為其主鍵趾徽,而且最好的是一個INT型的(推薦使用UNSIGNED)续滋,并設置上自動增加的AUTO_INCREMENT標志。
就算 users 表有一個 Unique 字段孵奶,比如身份證號碼疲酌,你也別讓它成為主鍵。因為使用 VARCHAR 類型來當主鍵會使用得性能下降了袁。
9. 使用 ENUM 而不是 VARCHAR
ENUM 類型是非忱士遥快和緊湊的。在實際上早像,其保存的是 TINYINT僻肖,但其外表上顯示為字符串。
如果你有一個字段卢鹦,比如“性別”臀脏,“國家”,“民族”冀自,你知道這些字段的取值是有限而且固定的揉稚,那么,你應該使用 ENUM 而不是 VARCHAR熬粗。
- Compact data storage in situations where a column has a limited set of possible values. The strings you specify as input values are automatically encoded as numbers. 字符串自動轉換為數字
- Readable queries and output. The numbers are translated back to the corresponding strings in query results.
CREATE TABLE shirts (
name VARCHAR(40),
size ENUM('x-small', 'small', 'medium', 'large', 'x-large')
);
INSERT INTO shirts (name, size) VALUES ('dress shirt','large'), ('t-shirt','medium'), ('polo shirt','small');
SELECT name, size FROM shirts WHERE size = 'medium';
每一個枚舉值都有一個索引 Index搀玖,從 1 開始∽つ牛空的枚舉值的索引為 0灌诅。
10. 盡可能的使用 NOT NULL
除非你有一個很特別的原因去使用 NULL 值芳来,你應該總是讓你的字段保持 NOT NULL。
不要以為 NULL 不需要空間猜拾,其需要額外的空間即舌,并且,在你進行比較的時候挎袜,你的程序會更復雜顽聂。
NULL columns require additional space in the row to record whether their values are NULL. For MyISAM tables, each NULL column takes one bit extra, rounded up to the nearest byte.
11. 數據表的分割
關于數據表的分割,參見另一篇文章 數據表的分割 學習筆記
12. 拆分大的 DELETE 或 INSERT 語句
如果你需要在一個在線的網站上去執(zhí)行一個大的 DELETE 或 INSERT 查詢盯仪,你需要非常小心紊搪,要避免你的操作讓你的整個網站停止相應。因為這兩個操作是會鎖表的全景,表一鎖住了耀石,別的操作都進不來了。
while (1) {
//每次只做1000條
mysql_query("DELETE FROM logs WHERE log_date <= '2009-11-01' LIMIT 1000");
if (mysql_affected_rows() == 0) {
// 沒得可刪了蚪燕,退出娶牌!
break;
}
// 每次都要休息一會兒
usleep(50000);
}
13. 無緩沖的查詢
正常的情況下,當你在當你在你的腳本中執(zhí)行一個SQL語句的時候馆纳,你的程序會停在那里直到這個SQL語句返回诗良,然后你的程序再往下繼續(xù)執(zhí)行。你可以使用無緩沖查詢來改變這個行為鲁驶。
關于這個事情鉴裹,在PHP的文檔中有一個非常不錯的說明: mysql_unbuffered_query() 函數:
“mysql_unbuffered_query() sends the SQL query query to MySQL without automatically fetching and buffering the result rows as mysql_query() does. This saves a considerable amount of memory with SQL queries that produce large result sets, and you can start working on the result set immediately after the first row has been retrieved as you don’t have to wait until the complete SQL query has been performed.”
上面那句話翻譯過來是說,mysql_unbuffered_query() 發(fā)送一個SQL語句到MySQL而并不像mysql_query()一樣去自動fethch和緩存結果钥弯。這會相當節(jié)約很多可觀的內存径荔,尤其是那些會產生大量結果的查詢語句,并且脆霎,你不需要等到所有的結果都返回总处,只需要第一行數據返回的時候,你就可以開始馬上開始工作于查詢結果了睛蛛。