MySQL性能优化点记录
第一章
myisam,可以基于blob和text的前500字節(jié),創(chuàng)建索引
myisam 支持fulltext
延遲更新索引
(delay_key_write)
CREATE TABLE `table3` (
? `id` INT(11) NOT NULL AUTO_INCREMENT,
? `name` VARCHAR(30) DEFAULT NULL,
? `id2` INT(11) DEFAULT NULL,
? PRIMARY KEY (`id`)
) ?ENGINE=MYISAM DEFAULT CHARSET=utf8 ?DELAY_KEY_WRITE = 1
ALTER TABLE table2 DELAY_KEY_WRITE = 1
只有myisam支持全文檢索
第三章 索引方面
? 字段盡可能的小
? 盡量避免null,用0代替。但是對性能的提升很小,最后考慮,索引的列最好不適用null
??
mysql性能優(yōu)化點記錄
一、優(yōu)化數(shù)據(jù)訪問
查詢性能低下的最基本原因就是訪問了太多數(shù)據(jù)。一些查詢不可避免的要篩選大量的數(shù)據(jù),單這并不常見。大部分性能欠佳的查詢都可以用減
少數(shù)據(jù)訪問的方式進行修改。在分析性能欠佳的查詢的時候,下面兩個步驟比較有用:
1.應用程序是否在獲取超過需要的數(shù)據(jù)。這通常是訪問了過多的行或列。
2.mysql服務器是否分析了超過需要的行。
對于訪問的數(shù)據(jù)行很大,而生成的結(jié)果中數(shù)據(jù)行很少,可以嘗試修改。
?
1.使用覆蓋索引,它存儲了數(shù)據(jù),所以存儲引擎不會去完整的行。
2.更改架構(gòu),一個例子就是使用匯總表。
3.重寫復雜的查詢,讓mysql的優(yōu)化器可以優(yōu)化的執(zhí)行。
?
二、復雜查詢和多個查詢
1.把一個復雜的查詢分解為多個簡單的查詢。(mysql一般的服務器,每秒鐘可以處理50 000個查詢)
2.
三、縮短查詢
將一次處理大量數(shù)據(jù)的操作,分解為多個小操作。循環(huán)的方式每次處理一部分數(shù)據(jù)。一次刪除不要超過10 000行(delete)
四、分解鏈接
把一個多表連接分解成多個單個查詢,然后在應用程序里實現(xiàn)聯(lián)接。
這樣的優(yōu)勢
1.緩存效率高。
2.mysql,可以更有效的利用表鎖,查詢會鎖住單個表較短時間。
3.應用程序進行聯(lián)接可以更方便的拓展數(shù)據(jù)庫,把不同表放在不同服務器上。
4.查詢更高效。
5.可以減少多余的行訪問,可以減少網(wǎng)絡流量和內(nèi)存消耗。
?小結(jié):在程序端進行聯(lián)接的效率更高
?1.可以緩存早期查詢的大量數(shù)據(jù)。
?2.使用了多個myisam表
?3.數(shù)據(jù)分布在不同的服務器上。
?4.對于大表使用in替換聯(lián)接
?5.一個連接引用了同一個表多次。
?
?當你重建匯總和緩存表的時候,在操作的時候你常常需要它們的數(shù)據(jù)保持可見。你可以使用“shadow?table”(影像表)來實現(xiàn)。當你已經(jīng)創(chuàng)建它之后,你可以使用原子性的重命名來交換這些表。舉個例子,如果
你需要重建my_summary,你能創(chuàng)建my_summary_new,填充數(shù)據(jù),把它和真正的表作交換。
mysql> DROP TABLE IF EXISTS my_summary_new, my_summary_old;
mysql> CREATE TABLE my_summary_new LIKE my_summary;
-- populate my_summary_new as desired
mysql> RENAME TABLE my_summary TO my_summary_old, my_summary_new TO my_summary;
?
?mysql執(zhí)行查詢的一般性過程
?1.客戶端發(fā)送查詢到服務器
?2.服務器檢查查詢緩存,
?3.服務器解析,預處理和優(yōu)化查詢,生成執(zhí)行計劃。
?4.執(zhí)行引擎調(diào)用存儲引擎api執(zhí)行查詢。
?5.服務器將結(jié)果發(fā)送到客戶端。
?
?mysql客戶端、服務器協(xié)議
?1.協(xié)議是半雙工的。mysql服務器在某個時間可以發(fā)送或者接受數(shù)據(jù),單不能同時發(fā)送和接收。所有沒有辦法階段消息。
?
?2.客戶端用一個數(shù)據(jù)包將查詢發(fā)送到服務器,所以max_packet_size這個配置參數(shù)對于大查詢很重要的原因。
?3.客戶端從服務器提取數(shù)據(jù)的時候是服務器產(chǎn)生數(shù)據(jù)的同時把它們“推”到客戶端的,客戶端只需要接收推出來的數(shù)據(jù),無法告訴服務器停止
發(fā)送數(shù)據(jù)。
?
?查詢緩存
?
?SELECT SQL_NO_CACHE * FROM ol_answerlog LIMIT 1000
?SHOW STATUS LIKE 'last_query_cost'
?
?
?關鍵字straight_join 強制執(zhí)行引擎按照查詢中表現(xiàn)的順序來進行鏈接操作。
嚴格的說,mysql不回嘗試減少讀取的行數(shù),它只會試著優(yōu)化對頁面的讀取,但是行數(shù)可以大致顯示查詢的開銷。
?連接優(yōu)化器試著產(chǎn)生最低開銷的查詢計劃。在可能的時候,他會從單表計劃開始,檢查所有的可能的子樹的組合。但是對n個表連接,需要檢
查組合的數(shù)量就是n的階乘,這個數(shù)量稱為ie搜索空間, 它增長非常快,如果一個查詢需要連接10個表,那么要檢查的數(shù)量將是10!=36288000?
當搜索空間非常巨大的時候優(yōu)化耗費的時間就會非常長,這時候服務器就不回執(zhí)行完整的分析,但表的數(shù)量超過optimizer_search_depth的值
時,它就會走捷徑,比如執(zhí)行所謂的 貪婪搜索。
?
SHOW TABLE STATUS FROM `servant_591up`WHERE ENGINE IS NOT NULL
AND NAME LIKE '%ol_ans%';
?
max min的優(yōu)化
select min(id) from ol_user where username = 'dddd@dd.com'
(一)max 和 min 會掃描整張表。
mysql的主鍵都是按照升序排列的。
可以使用limit 改寫查詢,
select userid from ol_user where username='test@nd.com' limit 1
(二)對同一表進行select 和 update
mysql不允許對一個表進行update的時候進行select
update tb1 as out_table
set cnt = (select count(*) from tb1 as inner_table where inner_table.type = outer_table.type);
一個實現(xiàn)方式:衍生表,當成臨時表來處理。
update tb1 inner join(
select type,count(*) as cnt
from tb1
group by type
)as der using(type)
set tb1.cnt = der.cnt;
(三、)優(yōu)化特定類型的查詢
1.count
count的作用 統(tǒng)計值的數(shù)量和統(tǒng)計行的數(shù)量
值是非空表達式(NOT NULL)
一個常見的錯誤就是在想統(tǒng)計行數(shù)的時候,在count的括號中放入列名,如果想知道結(jié)果的行數(shù),應該總是使用COUNT(*),這可以清晰的說明意
圖,并且得到好的性能。
2.MYISAM
只有在沒有WHERE條件的時候COUNT(*)才是最快的,在有條件過濾的時候并不非常快。
3.簡單優(yōu)化
可以利用MYISAM對COUNT(*)的優(yōu)化對已經(jīng)有索引的一小部分做統(tǒng)計。
SELECT COUNT(*) FROM WORD.CITY WHERE ID>5;
優(yōu)化為下面的語句
SELECT (SELECT COUNT(*) FROM CITY) - COUNT(*) FROM CITY WHEREID<=5;
這樣的explain只掃描6行數(shù)據(jù)
使用一個查詢統(tǒng)計同一列中不同值的數(shù)量。
select sum(if(color='blue',1,0)) as blue,sum(if(color='red',1,0)) as red from items;
下面是一個等價查詢
select count(color='blue' or null) as blue,count(color='red' or null) as red from items;
(四)優(yōu)化聯(lián)接
1.確保on 或using使用的列上有索引。
通常只需要在聯(lián)接中的第2個表上添加索引就可以。
2.確保group by或order by只引用一個表中的列。這樣可以使用索引。
3.謹慎升級mysql
(五)優(yōu)化子查詢
對于子查詢,盡可能的使用聯(lián)接。
(五)優(yōu)化group by和distinct
1.主要方式:索引
2.優(yōu)化group by的策略:臨時表或文件排序分組。
SQL_SMALL_RESULT : 強制使用臨時表
SQL_BIG_RESULT :強制使用文件排序
通常對表的id進行分組會更加高效
可以使用SQL_MODE參數(shù)禁止SELECT中使用在group by中出現(xiàn)的列
子查詢創(chuàng)建的臨時表不支持索引。
所以要讓子查詢創(chuàng)建的臨時表盡可能的小。
3.使用ROLL UP 優(yōu)化GROUP BY
WITH ROLLUP
最好的方式是將WITH ROLLUP 放在應用程序里。
注意: Rollup 與 order by 相互排拆?
(六)優(yōu)化limit和offset
LIMIT 和ORDER BY 一塊使用。
如果沒有索引,就使用文件排序。
(七)優(yōu)化SQL_CALC_FOUND_ROWS
這個地方很重要
一個技巧:在含有l(wèi)imit的查詢中添加SQL_CALC_FOUND_ROWS,這樣就可以知道沒有l(wèi)imit的時候會返回多少行數(shù)據(jù)。服務器會預測將會發(fā)現(xiàn)多少
行數(shù)據(jù)。但是服務器并不能真正的做到,只是告訴服務器生成結(jié)果并丟掉結(jié)果中不需要的部分。而不是在得到需要的數(shù)據(jù)后就立即停止。這個
選項代價很高。
一個非常好的設計:
如果每頁有20條結(jié)果,那么應該查詢limit 21行數(shù)據(jù),只顯示20條,如果結(jié)果中有21行,那么就會有下一頁。
另一種方式:就是提取并緩存大量數(shù)據(jù),比如1000行,然后從緩存中獲取后續(xù)頁面的數(shù)據(jù)。
可以讓程序知道一共有多少數(shù)據(jù),少于1000,程序知道有多少頁,如果大于1000,可以顯示找到的結(jié)果超過1000個。
這兩種都比重復產(chǎn)生完整的結(jié)果效率高。
如果以上兩種都不可以使用,可以使用覆蓋索引,使用單獨的count(*)會更好
(八)優(yōu)化聯(lián)合 union
mysql總是使用臨時表來執(zhí)行union,無法做更多的優(yōu)化
重要的是,一定要使用union all,除非真的是需要服務器消除重復的行,
否則mysql會使用distinct選項,來確保所有行數(shù)據(jù)的唯一性。
(九)查詢優(yōu)化提示
可以用一些提示控制優(yōu)化器的行為,每個提示只影響當前查詢。
1.HIGH_PRIORITY ?和 LOW_PRIORITY
HIGH_PRIORITY 讓mysql 將一個select語句放在其他的語句的前面,mysql將它放在隊列的前面,而不是在隊列中等待。可以用在insert語句中
。
low——priority正好相反,可以用在SELECT INSERT UPDATE REPLACE DELETE?
這兩個選項在表鎖的存儲過程中有效,在innerdb無效,在myisam要小心使用,嚴重影響性能,禁止并發(fā)插入。
2.delayed
用戶insert delete
立即返回,放入緩沖當中,,無法使用LAST_ISNERT_ID()
3.STRAIGHT_JOIN
強制mysql按照查詢中表出現(xiàn)的順序來連接表。
出現(xiàn)在兩個連接的表中間時,強制這兩個表按照順序連接。
用途:mysql沒有選擇更好的鏈接,或者優(yōu)化器需要花費很長時間來確定連接順序。
4.SQL_SMALL_RESULT SQL_BIGA_RESULT
用在group by 和distinct語句中的,如何使用臨時表
SQL_SMALL_RESULT :結(jié)果很小,可以放在索引過的臨時表中,
SQL_BIGA_RESULT:結(jié)果很大,最好使用磁盤上的臨時表進行排序。
5.SQL_BUFFER_RESULT
將結(jié)果放在臨時表中,并且要盡快釋放掉表鎖。
6.SQL_CACHE SQL_NO_CACHE
7.SQL_CALC_FOUND_ROWS
在limit自居計算完整的結(jié)果集,可以通過found_ROWS()來取得它的行數(shù),
最好不使用這個提示、
8.FOR_ UPDATE ?和 ? LOCK IN SHARE MODE
只有innodb支持,提示控制鎖定,僅對行鎖起作用。select語句中
9.USE INDEX 和 IGNORE INDEX ?和 ?FORCE INDEX
控制索引的使用,在mysql5.1中,還有 FOR ORDER BY ?FOR GROUP BY?
用途:告訴優(yōu)化器表掃描比索引代價高很多,
重要的系統(tǒng)變量
Optimizer_search_depth
優(yōu)化器檢查執(zhí)行計劃的深度。
Optimizer_prune_level
根據(jù)檢查的行數(shù)來決定跳過一些查詢計劃。
(九) 用戶自定義變量
一些需要注意的問題:
會禁止緩存
不能用于文字常量和標識的地方(表名,列名,limit)
和連接有關,不能跨通信使用
如果使用連接池,會引起代碼隔離
mysql 5.0大小寫敏感
不能顯示的聲明類型,最好的方式給變量顯示的一個初始值 0 ? 0.0 ?‘’,
用戶自定義變量的類型是動態(tài)的,賦值的時候才會變化。
優(yōu)化器有時候會把變量優(yōu)化掉。
set @ont:=1; :=運算符的優(yōu)先級,低于其他的,最好使用括號()。。 也可以使用=賦值,最好統(tǒng)一使用:=
未定義的變量不會引起語法錯誤,很容易犯錯。
五、mysql高級特性
查詢緩存命中率
Qcache_hits/(Qcache_his+Com_select) ? show status
1.緩存未命中原因
查詢不可緩存,不確定函數(shù)。CURRENT_DATE,結(jié)果太大, Qcache_not_cached 會記錄兩種無法緩存的查詢數(shù)量。
服務器以前從來沒見過這個緩存。
查詢結(jié)果被緩存過,但是服務器把它移除。
很多緩存失效。
2.很多緩存未命中,但是不能緩存的查詢很少。
查詢緩存未被激活。
服務器看到了以前未見過的查詢
緩存失效。
A:如何對查詢緩存進行維護調(diào)優(yōu)
Query_cache_type
表示緩存是否被激活,on off demand,demand:只有sql_cache的查詢才可以被緩存。
Query_cache_size
緩存的總內(nèi)存,字節(jié)單位。1024的倍數(shù),
Query_cache_min_res_unit
分配緩存塊的最小值
Query_cache_limit
限制了mysql存儲的最大結(jié)果。如果超過這個值,會丟掉已經(jīng)緩存過的值,并增加Query_not_chched的值。如果是這樣需要在查詢上增
加QUERY_NO_CACHE
Query_cache_wlock_invalidate
是否緩存其他鏈接已經(jīng)鎖定了的表,默認off,
B:優(yōu)化的一些法則
減少碎片
需要仔細選擇Query_cache_min_res_unit,可以避免在查詢緩存中造成大量的內(nèi)存浪費。
最佳設置根據(jù)典型查詢結(jié)果確定。可以使用內(nèi)存(Queryc_cache_size - Query_free_memory)除以Query_queries_in_cache
得到查 詢的平均大小。可以通過query_cache_limit的值來阻止緩存大結(jié)果。
可以檢查Qcache_free_blocks來探測緩存中碎片的情況,顯示緩存中有多少內(nèi)存塊出于free狀態(tài)。如果Qcache_free_blocks
大致 等于Qcache_total_blocks/2,則說明碎片非常嚴重,如果Qcache_lowmen_prunes的值在增加并且有大量的
自由塊,說明碎片導致查 詢整 被從緩存中永久刪除。
可以使用FLUSH QUERY CACHE命令移除碎片。會把所有的存儲塊向上移動,把自由塊移動到底部。會阻止訪問查詢緩存,鎖定
整個服務器,通常這個速度很快,不會移除緩存中的數(shù)據(jù),
RESET QUERY CACHE會清除緩存數(shù)據(jù)。
提高緩存可用性。
如果沒有碎片,但是命中率不高,應該給緩存分配較少的內(nèi)存。
服務器清理查詢的時候會Qcache_lowmen_prunes的值會增加,如果值增加的過快則說明:
1.如果自由塊很多,碎片
2.如果自由塊比較少,說明工作負載使用的內(nèi)存超過所分配的內(nèi)存。可以檢查Qcache_free_memory知道未使用的內(nèi)
存。
可以禁用緩存查看緩存是否真的有效果
query_cacha_size = 0,可以關閉緩存(query_cache_type 無法影響已經(jīng)打開了的鏈接,也不會把內(nèi)存歸還給服務
器。)
5.1.5 innodb和查詢緩存
6.2.2 myisam鍵緩存
SHOW VARIABLES LIKE 'key_buffer_size'
鍵緩沖區(qū),myisam本身只緩存索引,沒有數(shù)據(jù)。
應該讓key_buffer_size占到保留內(nèi)存的25-50%。但是對于mysql5.0,最大上限都是4G
但是可以創(chuàng)建多個命名鍵緩沖區(qū)。可以一次在內(nèi)存中保存4G以上的數(shù)據(jù)。
key_buffer_1 ?key_buffer_2 都是1G
在配置文件增加兩行?
key_buffer_1.key_buffer_size = 1G
key_buffer_2.key_buffer_size = 1G
可以使用cache index 命令把表映射到緩存
也可以用下面的命令把表的索引保存到key_buffer_1
cache index t1,t2 in key_buffer_1
也可以使用load index把表的索引預加載到緩存中
load index into cache t1,t2;
緩存命中率
100-((Key_reads * 100) / Key_read_requests)
緩存使用百分比
100-((Key_blocks_unused * key_cache_block_size) * 100 / key_buffers_size)
innodb 可以使用裸設備
?
raw
總結(jié)
以上是生活随笔為你收集整理的MySQL性能优化点记录的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 新能源汽车能保存多少度电?
- 下一篇: SQL Error (1130): Ho