經過用戶反饋獲取存在性能問題的SQLmysql
經過慢查日誌獲取存在性能問題的SQLsql
實時獲取存在性能問題的SQL數據庫
slow_quey_log=on 啓動記錄慢查詢日誌緩存
slow_query_log_file 指定慢查詢日誌的存儲路徑及文件(默認狀況下保存在MySQL的數據目錄中)服務器
long_query_time 指定記錄慢查詢日誌sql執行的閾值(默認爲10秒,一般改成0.001秒比較合適)session
log_queries_not_using_indexes 是否記錄未使用索引的SQL併發
set global sql_query_log=on;
socket
sysbench --test=./oltp.lua --mysql-table-engine=innodb --oltp-table-size=10000 --mysql-db=tests --mysql-user=sbtest --mysql-password=123456 --oltp-tables-count=10 --mysql-socket=/usr/local/mysql/data/mysql.sock run
工具
彙總除查詢條件外其它徹底相同的SQL並將分析結果按照參數中所指定的順序輸出性能
mysqldumpslow -s r -t 10 slow-mysql.log
-s order(c,t,l,r,at,al,ar)[指定按照哪一種排序方式輸出結果]
-t top[指定取前幾條做爲結束輸出]
pt-query-digest \
--explain h=127.0.0.1,u=root,p=p@ssWord \
slow-mysql.log
pt-query-digest --explain h=127.0.0.1 slow-mysql.log > slow.rep
select id,user,host,db,command,time,state,info FROM information_schema.processlist WHERE time>=60
》 對於一個讀寫頻繁的系統使用查詢緩存極可能會下降查詢處理的效率,建議你們不要使用查詢緩存
2.其中涉及的參數:
query_cache_type 設置查詢緩存是否可用[ON,OFF,DEMAND]
DEMAND表示只有在查詢語句中使用了SQL_CACHE和SQL_NO_CACHE來控制是否須要進行緩存
query_cache_size 設置查詢緩存的內存的大小
query_cache_limit 設置查詢緩存可用的存儲的最大值(加上SQL_NO_CACHE能夠提升效率)
query_cache_wlock_invalidate 設置數據表被鎖後是否返回緩存中的數據
query_cache_min_res_unit 設置查詢緩存分配的內存塊最小單位
3.MySQL依照這個執行計劃和存儲引擎進行交互
解析SQL,預處理。優化SQL的查詢計劃
語法解析階段是經過關鍵字對MySQL語句進行解析,並生成一顆對應的解析樹
MySQL解析器將使用MySQL語法規則驗證和解析查詢,包括檢查語法是否使用了正確的關鍵走;關鍵字的順序是否正確等等;
預處理階段是根據MySQL規則進一步檢查解析樹是否合法
檢查查詢中所涉及的表和數據列是否存在及名字或別名是否存在歧義等等
語法檢查經過了,查詢優化器就能夠生成查詢計劃了
優化器SQL的查詢計劃階段對上一步所生成的執行計劃進行選擇基於成本模型的最優的執行計劃【下面是影響選擇最優的查詢計劃的7因素】
1.統計信息不許確
2.執行計劃中的成本估算不等於實際的執行計劃的成本
3.MySQL優化器認爲的最優的可能與你認爲最優的不同【基於成本模型選擇最優的執行計劃】
4.MySQL從不考慮其餘的併發的查詢,這可能會影響當前查詢的速度
5.MySQL有時候也會基於一些固定的規則來生成執行計劃
6.MySQL不會考慮不受其控制的成本
查詢優化器在目前的版本中能夠進行優化的SQL的類型:
1.從新定義表的關聯順序
2.將外鏈接轉化爲內鏈接
3.使用等價變換規則
4.優化count(),min()和max()[select tables optimozed away]
5.將一個表達式轉化爲一個常數表達式
6.子查詢優化
7.提早終止查詢
8.對in()條件進行優化
複製代碼
使用profile[不建議使用,將來mysql中將被移除]
使用performance_schema
啓動所須要的監控和歷史記錄表的信息
update setup_instruments set enabled='yes',timed='yes' where name like 'stage%';
update setup_consumers set enabled='yes' where name like 'events%';
SELECT a.thread_id, sql_text, c.event_name, (c.timer_end - c.timer_start) / 1000000000 AS 'duration(ms)' FROM events_statements_history_long a JOIN threads b on a.thread_id=b.thread_id JOIN events_stages_history_long c ON c.thread_id=b.thread_id AND c.event_id between a.event_id and a.end_event_id WHERE b.processlist_id=CONNECTION_ID() AND a.event_name='statement/sql/select' ORDER BY a.thread_id,c.event_id
大表的更新和刪除
delimiter $$
use 'imooc'$$
drop procedure if exists 'p_delete_rows'$$
create definer='root'@'127.0.0.1' procedure 'p_delete_rows'()
begin
declare v_rows int;
set v_rows int,
while v_rows=1,
while v_rows>0
do
delete from test where id>=9000 and id<=19000 limit 5000;
select row_count() into v_rows;
select sleep(5);
end while;
end $$
delimiter;
複製代碼
如何修改大表的表結構
1.對錶中的列的字段類型進行修改改變字段的寬度時仍是會進行鎖表
2.沒法解決主從數據庫延遲的問題
修改的方法:
pt-online-schema-change
--alter="modify c varchar(150) not null default''"
--user=root --password=PassWord D=testDataBaseName,t=tesTableName
--charset=utf-8 --execute
複製代碼
如何優化not in和<>查詢
#原始的SQL語句
SELECT
customer_id,
first_name,
last_name,
email
FROM
customer
WHERE
customer_id NOT IN (
SELECT
customer_id
FROM
payment
)
#優化後的SQL語句
SELECT
a.customer_id,
a,
first_name,
a.last_name,
a.email
FROM
customer a
LEFT JOIN payment b ON a.customer_id = b.customer_id
WHERE
b.customer_id IS NULL
複製代碼
使用匯總表的方法進行優化 #統計商品的評論數(如有上億條記錄,執行起來很是慢進行全表掃描)[優化前的SQL] select count(*) from product_comment where product_id=999;
#彙總表就是提早以要統計的數據進行彙總並記錄到數據庫中以備後續的查詢使用
create table product_comment_cnt(product_id int,cnt int);
#統計商品的評論數[優化後的SQL]
#查詢出每一個商品截止到前一天的累計評論數+當天的評論數
select sum(cnt) from(
select cnt from product_comment_cnt where product_id=999
union all
select count(*) from product_comment where product_id=999
and timestr>DATE(NOW())
) a複製代碼