面試資料

IT面試html

http://www.mianwww.com/html/category/company-list/sina前端

2016十家公司前端面試小記

http://www.cnblogs.com/xxcanghai/p/5205998.htmlmysql

 

http://www.kanzhun.com/gsm3146c7.html?sortMethod=1&result=0&q=面試

 

hash算法算法

http://dev.yesky.com/261/35374761.shtmlsql

 

http://m.oschina.net/blog/194326編程

高性能MySQL-3rd-(六)查詢性能優化

zhmsong 發佈於 2年前,共有 0 條評論緩存

/* *  --------------------------------------------------------            
 *     高性能MySQL-3rd-Baron Schwartz-筆記             
 *     第六章 查詢性能優化    
 */  --------------------------------------------------------

 

======================================================性能優化

    6.1 爲何查詢速度會變慢服務器

    查詢有生命週期大體順序:從客戶端,到服務器,而後在服務器上進行解析,生成執行計劃,執行,返回結果給客戶端,其中執行是最重要的階段。包括了大量的檢索數據到存儲引擎的調用,調用後的數據處理,分組和排序。

    查詢在每一個部分都會花費時間,包括網絡、CPU計算、生成執行計劃、鎖等待(互斥等待),尤爲是向存儲引擎調用操做,這些調用須要在內存操做、在CPU操做、內存不足時致使I/O操做。

    瞭解以上就可能知道查詢速度會變慢的思考角度。

======================================================

    6.2 慢查詢基礎:優化數據訪問

    優化數據訪問,就是優化訪問的數據,操做對象是要訪問的數據,兩方面,是否向服務器請求了大量不須要的數據,二是是否逼迫MySQL掃描額外的記錄(沒有必要掃描)。

    請求不須要數據的典型案例:不加LIMIT(返回所有數據,只取10條)、多表關聯Select * 返回所有列(多表關聯查詢時*返回多個表的所有列)、仍是Select *(可能寫程序方面或代碼複用方面有好處,但還要權衡)、重複查詢相同數據(真須要這樣,能夠緩存下來,移動開發這個頗有必要本地存儲)。

    標誌額外掃描的三個指標:響應時間(本身判斷是否合理值)、掃描的行數、返回的行數,通常掃描行數>返回行數。

    掃描的行數須要與一個「訪問類型」概念關聯,就是 Explain 中的 type,explain的type結果由差到優分別是:ALL(全表掃描)、index(索引掃描)、range(範圍掃描)、ref(惟一索引查詢 key_col=xx)、const(常數引用)等。從「訪問類型」能夠明白,索引讓 MySQL 以最高效、掃描行數最少的方式找到須要的記錄。

    書中有個例子,說明在where中使用已經是索引的列和取消該列的索引後兩種結果,type由ref變爲All,預估要訪問的rows從10變爲5073,差別很是明顯。

======================================================

    6.3 重構查詢的方式

    第一:將一個複雜查詢拆分爲數個小且簡單的查詢,數據返回也快。

    第二:切分查詢,如刪除10萬條數據,能夠切分爲10次,每次刪除1萬條。

    第三:分解關聯查詢:

    以上作法好處是,充分利用前一步緩存,減小鎖競爭,in(123, 456,...)也更高效,減小冗餘記錄,等等。

======================================================

    6.4 查詢執行的基礎(知識)

    MySQL執行查詢執行路徑,以下圖,關鍵要解釋的是 客戶端發送請求,若是查詢緩存有結果,則直接返回。

   

 

    客戶端/服務器通信協議,具體細節不關注,只知道它是「半雙工」工做,要麼客戶端向服務器發送數據,要麼服務器向客戶端發送數據,兩個動做不會同時發生;另外,發送數據都只有發送完成後才能動做,這就是爲何要加LIMIT。

    另外,注意當客戶端從服務器獲取數據時,看起來是從服務器獲取數據,其實是從庫函數的緩存中獲取數據,想一想PHP的 mysql_query(),此時數據已經到了PHP的緩存中,而mysql_unbuffered_query()不會緩存結果。

    MySQL中的關聯(join)查詢,整體來講,MySQL認爲任何一個查詢都是一次關聯,不光是查詢兩個表匹配才叫關聯。因此,理解MySQL如何執行關聯查詢相當重要。MySQL的關聯是:嵌套循環關聯,舉例以下:

 

    結合書中關於多表關聯的案例,參考一個實際例子 《MySQL SQL優化之 STRAIGHT_JOIN》 全面介紹優化過程。

    排序優化,無論怎麼樣,從性能角度,應該儘量避免排序,或者儘量避免對大量數據進行排序。第三章講了索引排序,快速,當不能直接使用索引時,MySQL就會本身進行排序,數據量小時在內存中排序,數據量大時使用到磁盤。量小於「排序緩衝區」時,MySQL使用內存進行「快速排序」。若是內存不夠,MySQL先將數據分塊,每塊使用快速排序,而後將各塊結果放在硬盤上,而後合併(merge),最後返回排序結果。

    注意:MySQL排序過程統稱爲文件排序(filesort),概念上的,即便排序發生在內存,而不是磁盤文件中。

    MySQL有兩種排序算法,兩次傳輸排序(舊版)、單次傳輸排序(新版)。兩種各有各的最好和最差的應用場景,注意 max_length_for_sort_data 是臨界值,不超過期使用單次傳輸,超過使用兩次傳輸。MySQL自動判斷,具體參考第八章中「文件排序優化」。

    兩次傳輸排序(舊版),讀取行指針和須要排序的字段,對其進行排序,而後再根據排序結果讀取所須要的數據行。顯然是兩次傳輸,特別是讀取排序後的數據時(第二次)大量隨機I/O,因此兩次傳輸成本高。

    單次傳輸排序(新版),一次讀取出全部須要的或SQL查詢指定的列,而後根據排序列,排序,直接返回排序後的結果。順序I/O,缺點:若是列多,額外佔用空間。

    注意:MySQL排序時使用的空間比想象大不少,爲何?由於MySQL要爲每個排序記錄分配足夠長的空間存放,VARCHAR滿長度(聲明的完整長度),使用UTF8字符集時,爲每一個字符預留3個字節。因此會很大!

    結合關聯查詢,排序會更復雜。若是ORDER BY排序列都在第一個表(驅動表),那麼在關聯處理時,先對驅動表排序,Explain結果中Extra會有Using filesort;除此以外全部狀況,都會在關聯結束後,將結果放在臨時表中進行最終排序,Extra中會有Using temporary;Using filesort。若是還有LIMIT,也會在排序後應用。能夠,排序須要的空間大!

    注意:MySQL5.6之後,有所優化,若是有LIMIT會只排序須要的,而不是全部,拋棄不知足條件的結果。

   查詢執行引擎,相對於查詢優化,查詢執行簡單些了,MySQL只根據執行計劃輸出的指令逐步執行。指令都是調用存儲引擎的API來完成,通常稱爲 handler API,實際上,MySQL優化階段爲每一個表都建立了一個 handler 實例,(相似於VC++編程中的句柄?),用 handler 實例獲取表的信息(列名、索引統計信息等)。

    注意:存儲引擎接口不豐富,底層僅幾十個,但功能豐富!如某接口實現了查詢第一行,又有一個接口實現了查詢下一行,有了這兩個就能夠全表掃描了!

    返回結果給客戶端,有結果集返回結果集,沒結果,返回影響的行數。通常MySQL也會將這個結果緩存下來,存放到查詢緩存中。

    注意:MySQL返回結果是一個增量、逐步返回的過程,例如,關聯操做中,當一個嵌套循環處理到最後一個關聯表,並開始生成第一條結果時,MySQL就能夠開始向客戶端逐步返回結果集了。好處:服務器端無須存儲太多結果,也不會由於返回的結果太多而消耗太多內存,也使客戶端第一時間得到返回結果。結果是以TCP協議封包發送的,TCP的傳輸過程,可能會對封包進行緩存而後批量發送。

======================================================

    6.5 MySQL查詢優化器的侷限性

    不熟悉 JOIN USING 和 JOIN ON 的請看 紅薯做品 MySQL 三種關聯查詢的方式: ON vs USING vs 傳統風格

    一個是關聯子查詢,沒看明白,回來再讀。

    一個UNION限制,沒法將限制條件從外層下推到內層,改造例子以下

 

    等值傳遞:講的IN列表,MySQL會將IN列表的值傳到各個過濾子句,若是IN列表太大,會形成額外消耗,優化和執行都很慢。

    並行執行,MySQL沒法執行並行查詢,不用白費力氣了。

    哈希關聯,MySQL不支持哈希關聯,全部關聯都是嵌套循環關聯。

    鬆散索引掃描,MySQL不支持鬆散(跳躍),仍須要掃描每個條目。

    最大值和最小值,MySQL對 MIN()和MAX()作得很差。看一個例子,強制使用索引來優化(use index(xx))。

    在同一個表上查詢和更新,MySQL不容許這樣。

======================================================

    6.6 查詢優化器的提示(hint)

    講到了不少提示,意在若是咱們對優化器選擇的執行計劃不滿意,使用提示來控制最終的執行計劃,如上面的 USE INDEX(PRIMARY),其餘還有:HIGH_PRIORITY、LOW_PRIORITY、DELAYED、STRAIGHT_JOIN(上文提到過)、SQL_SMALL_RESULT、SQL_BIG_RESULT、SQL_BUFFER_RESULT、SQL_CACHE、SQL_NO_CACHE、SQL_CALC_FOUND_ROWS、FOR UPDATE、LOCK IN SHARE MODE、USE INDEX、IGNORE INDEX、FORCE INDEX等等。

======================================================

    6.7 優化特定類型的查詢

    6.7.1 優化 COUNT()查詢

    COUNT()常被誤解(難道這本書裏說的對的?),COUNT()有兩個做用,一、統計非NULL列的列植的數量,二、統計返回數據集的行數;經常使用的是COUNT(*),*常被誤解爲全部列,實際上在操做時是忽略全部列,而直接統計全部行數。COUNT(*)中的*與SELECT *中的*是不一樣的。若是你真想統計結果集的行數,就用 COUNT(*)而不要使用 COUNT(aCol)。

   一般覺得 MyISAM執行COUNT(*)最快,其實是有條件的,只有不用 WHERE時,由於MySQL根本不用掃描數據行,也無須去計算,會直接利用存儲引擎的特性去得到這個值。當帶上 WHERE 上,就須要去掃描去計算了。

   書中一個優化的例子,將條件反轉後可大大加速,如查詢 id > 5 的數量有4097行,而反轉,查詢 id < 5 的,只有幾行,而後 用總行數(用 COUNT(*) 獲取-常數不費計算)減去 id < 5的,大大優化。但這種狀況貌似我提早能夠知道 id > 5的數據比 id < 5 的數據多不少才能夠。

   能使用近似值的就沒必要追求精確計算值,代價過高!

   6.7.2 優化關聯查詢

   這個話題基本整本書都在討論(仍是很暈),注意一下:

   1)確保ON或USING子句中的列上有索引,在建立索引時就要考慮到關聯的順序。

相關文章
相關標籤/搜索