爲何查詢速度會慢mysql
1.慢是指一個查詢的響應時間長。一個查詢的過程:laravel
2.數據訪問sql
3.查詢的方式數據庫
慢查詢分析緩存
問題SQL性能優化
把複雜的SQL分紅多個簡單SQL並執行,查看具體那個字段會慢,區分度不高。服務器
EXPLAIN函數
顯示SQL如何使用索引的執行計劃。性能
執行計劃的參數:優化
table 顯示這一行的數據是關於哪張表的
type 顯示鏈接使用了何種類型。從最好到最差的鏈接類型爲const、eq_reg、ref、range、indexhe和ALL
possible_keys 顯示可能應用在這張表中的索引。若是爲空,沒有可能的索引。能夠爲相關的域從WHERE語句中選擇一個合適的語句
key 實際使用的索引。若是爲NULL,則沒有使用索引。不多的狀況下,MYSQL會選擇優化不足的索引。這種狀況下,能夠在SELECT語句中使用USE INDEX(indexname)來強制使用一個索引或者用IGNORE INDEX(indexname)來強制MYSQL忽略索引
key_len 使用的索引的長度。在不損失精確性的狀況下,長度越短越好
ref 顯示索引的哪一列被使用了,若是可能的話,是一個常數
rows 掃描請求數據的行數
Extra 關於MYSQL如何解析查詢的額外信息
PROFILE
顯示SQL執行消耗系統資源的信息。
查詢執行的過程
MySQL客戶端/服務器通訊協議是「半雙工」的。客服端/服務器端均可以向對方發送數據,但不能同時發生。因此咱們沒法也無須將一個消息切成小塊獨立來發送。
這種協議沒辦法進行流量控制。
客戶端發送請求的數據包大小由參數max_allowed_packet限制。若是查詢太大,服務端會拒絕接受更多的數據並拋出相應的錯誤。
服務器端返回的多個數據包,客戶端必須完整接受。
1.查詢狀態 SHOW FULL PROCESSLIST
mysql>SHOW FULL PROCESSLIST; Id User Host db Command Time State Info ------ ------ --------------- ------------ ------- ------ ------ ----------------------- 1 root localhost:61316 laravel_blog Query 0 (NULL) show FULL processlist 2 root localhost:61319 (NULL) Sleep 94 (NULL)
對於一個鏈接,或者說一個線程,任什麼時候刻都有一個狀態,該狀態表示了MySQL當前正在作什麼。
2.查詢緩存
-- 查看緩存是否開啓 (query_cache_type 爲 ON 表示已經開啓
mysql> show variables like '%query_cache%';
+------------------------------+----------+ | Variable_name | Value | +------------------------------+----------+ | have_query_cache | YES | | query_cache_limit | 1048576 | | query_cache_min_res_unit | 4096 | | query_cache_size | 20971520 | | query_cache_type | ON | | query_cache_wlock_invalidate | OFF | +------------------------------+----------+
檢查sql是否命中緩存。命中則檢查一次用戶權限後返回,這個檢查是經過一個對大小寫敏感的哈希查找實現的。兩次查詢只要有一個字節的不一樣就會失敗。不然將進入下一個階段。
當sql中有不肯定的數據時,則不會被緩存。例如用戶自定義函數、存儲函數、用戶變量、臨時表、mysql庫中的系統表,其查詢結果都不會被緩存。
3.查詢優化
語法解析器和預處理
MySQL經過關鍵字將sql語句進行解析,並生成一顆對應的解析樹。這個過程解析器主要經過語法規則來驗證和解析。好比sql中是否使用了錯誤的關鍵字或者關鍵字的順序是否正確等。預處理則會根據MySQL規則進一步檢查解析樹是否合法。好比檢查要查詢的數據表和數據列是否存在等。
查詢優化器
通過前面的步驟生成的語法樹被認爲是合法的了,而且由優化器將其轉化成查詢計劃。多數狀況下,一條查詢能夠有不少種執行方式,最後都返回相應的結果。優化器的做用就是找到這其中最好的執行計劃。
MySQL使用基於成本的優化器,經過計算成本選擇其中最小的一個。經過SHOW STATUS LIKE 'Last_query_cost';查當作本。成本的最小單位是隨機讀取一個4K數據頁的成本。
MySQL的查詢優化器是一個很是複雜的部件,它使用了很是多的優化策略來生成一個最優的執行計劃:
上面列舉了一些,隨着MySQL的不斷髮展,優化器使用的優化策略也在不斷的進化。
查詢執行引擎
在完成解析和優化階段之後,MySQL會生成對應的執行計劃,查詢執行引擎根據執行計劃給出的指令逐步執行得出結果。整個執行過程的大部分操做均是經過調用存儲引擎實現的接口來完成,這些接口被稱爲handler API。查詢過程當中的每一張表由一個handler實例表示。實際上,MySQL在查詢優化階段就爲每一張表建立了一個handler實例,優化器能夠根據這些實例的接口來獲取表的相關信息,包括表的全部列名、索引統計信息等。存儲引擎接口提供了很是豐富的功能,但其底層僅有幾十個接口,這些接口像搭積木同樣完成了一次查詢的大部分操做。
返回結果
查詢執行的最後一個階段就是將結果返回給客戶端。即便查詢不到數據,MySQL仍然會返回這個查詢的相關信息,好比該查詢影響到的行數以及執行時間等。
若是查詢緩存被打開且這個查詢能夠被緩存,MySQL也會將結果存放到緩存中。
結果集返回客戶端是一個增量且逐步返回的過程。有可能MySQL在生成第一條結果時,就開始向客戶端逐步返回結果集了。這樣服務端就無須存儲太多結果而消耗過多內存,也可讓客戶端第一時間得到返回結果。須要注意的是,結果集中的每一行都會以一個知足①中所描述的通訊協議的數據包發送,再經過TCP協議進行傳輸,在傳輸過程當中,可能對MySQL的數據包進行緩存而後批量發送。
性能優化
優化count()查詢
count()是一個特殊的函數。能夠統計行數、某個列值的數量。在統計列值時要求列值是非空的(不統計NULL)。在統計行數時count(*)不會被擴展成全部的列,而是忽略全部的列。這樣寫意義清晰,性能好。
優化LIMIT分頁
LIMIT 10000,20這樣的查詢,MySQL須要查詢10020條記錄後返回最後20記錄。通常優化爲WHERE id>10000 LIMIT 20。其餘優化關聯一個冗餘表,冗餘表只包含主鍵列和須要排序的數據列。
數據類型優化
選擇數據類型的原則:更小的一般更好、簡單就好、儘可能避免NULL。
更小的數據類型一般會更快,由於佔用更少的磁盤、內存和CPU緩存。
簡單的數據類型須要更少的CPU週期。例:int比char的操做代價低。
這裏總結幾個可能容易理解錯誤的技巧:
一般來講把可爲NULL的列改成NOT NULL不會對性能提高有多少幫助,只是若是計劃在列上建立索引,就應該將該列設置爲NOT NULL。
對整數類型指定寬度,好比INT(11),沒有任何卵用。INT使用32位(4個字節)存儲空間,那麼它的表示範圍已經肯定,因此INT(1)和INT(20)對於存儲和計算是相同的。
UNSIGNED表示不容許負值,大體可使正數的上限提升一倍。好比TINYINT存儲範圍是-128 ~ 127,而UNSIGNED TINYINT存儲的範圍倒是0 - 255。
一般來說,沒有太大的必要使用DECIMAL數據類型。即便是在須要存儲財務數據時,仍然可使用BIGINT。好比須要精確到萬分之一,那麼能夠將數據乘以一百萬而後使用BIGINT存儲。這樣能夠避免浮點數計算不許確和DECIMAL精確計算代價高的問題。
TIMESTAMP使用4個字節存儲空間,DATETIME使用8個字節存儲空間。於是,TIMESTAMP只能表示1970 - 2038年,比DATETIME表示的範圍小得多,並且TIMESTAMP的值因時區不一樣而不一樣。
大多數狀況下沒有使用枚舉類型的必要,其中一個缺點是枚舉的字符串列表是固定的,添加和刪除字符串(枚舉選項)必須使用ALTER TABLE(若是隻只是在列表末尾追加元素,不須要重建表)。
schema的列不要太多。緣由是存儲引擎的API工做時須要在服務器層和存儲引擎層之間經過行緩衝格式拷貝數據,而後在服務器層將緩衝內容解碼成各個列,這個轉換過程的代價是很是高的。若是列太多而實際使用的列又不多的話,有可能會致使CPU佔用太高。
大表ALTER TABLE很是耗時,MySQL執行大部分修改表結果操做的方法是用新的結構建立一個張空表,從舊錶中查出全部的數據插入新表,而後再刪除舊錶。尤爲當內存不足而表又很大,並且還有很大索引的狀況下,耗時更久。固然有一些奇技淫巧能夠解決這個問題,有興趣可自行查閱。
索引的設計
索引的優勢:大大減小了服務器須要掃描的數據量、幫主服務器避免排序和臨時表、能夠將隨機I/O變爲順序I/O;
「三星系統」:索引將相關的記錄放到一塊兒則得到一星;若是索引中的數據順序和查找中的排序順序一致則得到二星;若是索引中的列包含了查詢中須要的所有列則得到三星。
注:若是在EXPLAIN中看到有索引合併(Extra字段出現Using union),應該好好檢查一下查詢和表的結構,看是否是已是最優的。
參考資料
Baron Scbwartz 等著;寧海元 周振興等譯;高性能MySQL(第三版); 電子工業出版社, 2013