https://blog.csdn.net/DrDanger/article/details/79092808 https://blog.csdn.net/wildpen/article/details/81335777 |
用戶傳入sql-----查詢緩存(命中緩存可直接返回結果)----解析器(生成sql解析樹)----預處理器(可能sql等價改寫)-----查詢優化器(生成sql執行計劃)----查詢執行引擎----結果返回給用戶。 |
優化器是數據庫的一個核心子系統,你也能夠把他理解爲MySQL數據庫中的一個核心模塊或者一個核心功能模塊。 |
2.優化器的目的:php
優化器的目的是按照必定原則來獲得她認爲的目標SQL在當前情形下最有效的執行路徑,優化器的目的是爲了獲得目標SQL的執行計劃. |
3.優化器分類:mysql
傳統關係型數據庫裏面的優化器分爲CBO和RBO兩種。 RBO--- Rule_Based Potimizer 基於規則的優化器:redis RBO :RBO所用的判斷規則是一組內置的規則,這些規則是硬編碼在數據庫的編碼中的,RBO會根據這些規則去從SQL諸多的路徑中來選擇一條做爲執行計劃(好比在RBO裏面,有這麼一條規則:有索引使用索引。那麼全部帶有索引的表在任何狀況下都會走索引)因此,RBO如今被不少數據庫拋棄(oracle默認是CBO,可是仍然保留RBO代碼,MySQL只有CBO)sql RBO最大問題在於硬編碼在數據庫裏面的一系列固定規則,來決定執行計劃。並無考慮目標SQL中所涉及的對象的實際數量,實際數據的分佈狀況,這樣一旦規則不適用於該SQL,那麼極可能選出來的執行計劃就不是最優執行計劃了。數據庫 CBO---Cost_Based Potimizer 基於成本的優化器:緩存 CBO :CBO在會從目標諸多的執行路徑中選擇一個成本最小的執行路徑來做爲執行計劃。這裏的成本他實際表明了MySQL根據相關統計信息計算出來目標SQL對應的步驟的IO,CPU等消耗。也就是意味着數據庫裏的成本實際上就是對於執行目標SQL所須要IO,CPU等資源的一個估計值。而成本值是根據索引,表,行的統計信息計算出來的。(計算過程比較複雜)服務器 |
4.Cardinality的解釋:基數。多線程
Cardinality是CBO特有的概念,它是指指定集合包含的記錄數,說白了就是指定結果集的行數。Cardinality和成本值的估計息息相關,由於MySQL的指定結果集所消耗的io資源能夠近似看作隨着該結果集的遞增而遞增。 經過SHOW INDEX結果中的列Cardinality來觀察。 對於Cardinality總結:架構 1. 列值表明的是此列中存儲的惟一值的個數(若是此列爲primary key 則值爲記錄的行數)oracle 2. 列值只是個估計值,並不許確。 3. 列值不會自動更新,須要經過Analyze table來更新一張表或者mysqlcheck -Aa來進行更新整個數據庫。 4. 列值的大小影響Join時是否選用這個Index的判斷。 |
5.Selectivity:可選擇率:
可選擇率也是CBO特有的概念,它是指施加指定條件後返回結果集的記錄數佔未施加任何謂詞條件的原始結果集的記錄數的比率(謂詞條件,能夠理解爲where等限定詞進行限定) selectivity(可選擇率)=施加指定謂詞條件後返回結果集的記錄數/未施加指定謂詞條件的結果集的記錄數,咱們能夠經過可選擇率的估計,來肯定一個列上是否須要添加索引,實際上,MySQL的CBO也是經過可選擇率來肯定是否走索引,值越大在作錶鏈接的時候,就越有機會選擇這個索引。 |
6.執行計劃
1. 查詢優化器使用統計信息爲SQL選擇執行計劃。 2. mysql沒有數據直方圖也沒法手工刪除統計信息。 3. 在服務器層有查詢優化器,卻沒有保存數據和索引統計信息。統計信息由存儲引擎實現,不一樣的存儲引擎會存儲不一樣的統計信息。 4. 統計信息分爲索引的統計信息,表的統計信息。 統計信息的收集:mysql> analyze table t1; Analyze table收集表和索引統計信息,適用於MyISAM和InnoDB。對於INNODB存儲引擎,在如下狀況下,會從新收集統計信息。 1. 表第一次打開的時候。 2. 表修改的行超過1/16 或者新插入20億行的時候計算索引的統計信息。 3. 執行show index或者查詢information schema下的表。 |
7.統計信息的查看:
索引統計信息: Show index from table或information_schema.statistics表 表統計信息: Show table status like或information_schema.tables表 |
8.查看執行計劃
mysql> explain select * from employees.employees limit 1\G; *************************** 1. row *************************** id: 1 select_type: SIMPLE 查詢類型 table: employees 當前查詢被掃描到的表 多是表的別名 partitions: NULL type: ALL 表掃描方式 possible_keys: NULL 可能被使用到的索引 key: NULL 被使用的索引 key_len: NULL 使用過的索引的長度 ref: NULL rows: 299246 掃描的數據的行數(examin) filtered: 100.00 (返回比例) Extra: NULL 額外的說明 id列:通常狀況下若是不帶子查詢,id不增長.若是有子查詢的,自查詢數字增長,先執行子查詢,即數據大的先執行.(從大到小). select_type列:simple 簡單查詢(不帶子查詢) PRIMARY 子查詢最外層查詢 SUBQUERY(不在 from後面子查詢) DEPENDENT SUBQUERY DERIVED(在 from子句中的子查詢) union:在union關鍵字的後的select語句 union result:採用匿名臨時進行檢索結果 table列:這列表示正在訪問某個表 type:查詢類型: 查詢效率依次降低. (system---const---eq_ref---ref---fulltext---ref_of_null----index_merge---unique_subquery---index_subquery---range---index----all) ALL ----全表掃描 index----按照索引的次序進行全表掃描 range-----索引範圍掃描 ref-----索引直接獲取單個數據 const----- -經過主鍵直接返回數據 執行計劃列: id列:用於表示select的列,若是都是簡單查詢則都是1,若是有子查詢,則會進行增長,數據大的先執行。 查看執行計劃的規則:(最大最上規則) 1.id相同,執行順序由上至下 2.id不一樣,若是是子查詢,id序號會遞增,id值越大優先級越高,越先被執行。 3.id既有相同的,又有不一樣的。id若是相同認爲是一組,執行順序由上至下; 在全部組中,id值越大優先級越高,越先執行。 possible_keys列:可能會使用那些索引 key列:使用到的索引 Key_len列:索引長度列.可根據索引的使用長度來判斷複合索引的使用狀況. Ref列:索引中查找到的值所用的列或者常量 rows列:MySQL須要掃描的行數 table列:這列表示正在訪問某個表. Select type 列的值有: 1.PRIMARY:查詢中包含任何複雜的子部分,最外層的查詢 2.SUBQUERY:SELECT或WHERE中包含的子查詢部分(不是from後的子查詢). 3.DERIVED:在FROM中包含的子查詢被標記爲DERIVER(衍生), MySQL會遞歸執行這些子查詢,把結果放到臨時表中。 4.UNION:若第二個SELECT出現UNION,則被標記爲UNION, 若UNION包含在FROM子句的子查詢中,外層子查詢將被標記爲DERIVED。 5.UNION RESULT:從UNION表獲取結果的SELECT 6.simple:簡單查詢,不包括子查詢和union. type列:查詢類型:(12種) system---const---eq_ref---ref---fulltext---ref_of_null----index_merge---unique_subquery---index_subquery---range---index----all 說明:按照此順序查詢效率依次降低。 (subquery:子查詢) Extra列的值: 1.using filesort須要使用額外的排序獲得結果(進行內存排序或者硬盤排序) 2.using index 優化器只須要使用索引就能夠返回結果(覆蓋索引) 3.using index condition 優化器使用index condition pushdown優化 4.using join buffer 優化器須要在使用join buffer 5.using mrr 優化器使用mrr優化 6.using tpporary 優化器須要使用臨時表 7.using where 優化器使用where過濾 |
通常來講,得保證查詢至少達到range級別,最好能達到ref。 system:表只有一行記錄(等於系統表),這是const類型的特例,平時不會出現 const:若是經過索引依次就找到了,const用於比較主鍵索引或者unique索引。 由於只能匹配一行數據,因此很快。若是將主鍵置於where列表中,MySQL就能將該查詢轉換爲一個常量 eq_ref:惟一性索引掃描,對於每一個索引鍵,表中只有一條記錄與之匹配。常見於主鍵或惟一索引掃描 ref:非惟一性索引掃描,索引直接獲取單個數據,返回匹配某個單獨值的全部行。本質上也是一種索引訪問,它返回全部匹配 某個單獨值的行,然而它可能會找到多個符合條件的行,因此它應該屬於查找和掃描的混合體 range:只檢索給定範圍的行,使用一個索引來選擇行。key列顯示使用了哪一個索引,通常就是在你的where語句中出現between、<</font>、>、in等的查詢,這種範圍掃描索引比全表掃描要好,由於只須要開始於縮印的某一點,而結束於另外一點,不用掃描所有索引 index:Full Index Scan ,index與ALL的區別爲index類型只遍歷索引樹,這一般比ALL快,由於索引文件一般比數據文件小。 (也就是說雖然ALL和index都是讀全表, 但index是從索引中讀取的,而ALL是從硬盤讀取的) all:Full Table Scan,遍歷全表得到匹配的行 |
1、Using filesort: 說明MySQL會對數據使用一個外部的索引排序,而不是按照表內的索引順序進行讀取。MySQL中沒法利用索引完成的排序操做稱爲「文件排序」 2、Using temporary: 使用了臨時表保存中間結果,MySQL在對查詢結果排序時使用臨時表。常見於排序order by和分組查詢group by 3、Using index: 表示相應的SELECT操做中使用了覆蓋索引(Covering Index),避免訪問了表的數據行,效率不錯。 若是同時出現using where,代表索引被用來執行索引鍵值的查找; 若是沒有同時出現using where,代表索引用來讀取數據而非執行查找動做 覆蓋索引(Covering Index): 理解方式1:SELECT的數據列只須要從索引中就能讀取到,不須要讀取數據行,MySQL能夠利用索引返回SELECT列表中 的字段,而沒必要根據索引再次讀取數據文件,換句話說查詢列要被所建的索引覆蓋 理解方式2:索引是高效找到行的一個方法,可是通常數據庫也能使用索引找到一個列的數據,所以他沒必要讀取整個行。 畢竟索引葉子節點存儲了他們索引的數據;當能經過讀取索引就能夠獲得想要的數據,那就不須要讀取行了,一個索引 包含了(覆蓋)知足查詢結果的數據就叫作覆蓋索引 注意: 若是要使用覆蓋索引,必定要注意SELECT列表中只取出須要的列,不可SELECT *, 由於若是全部字段一塊兒作索引會致使索引文件過大查詢性能降低 6、impossible where: WHERE子句的值老是false,不能用來獲取任何元組 7、select tables optimized away: 在沒有GROUP BY子句的狀況下基於索引優化MIN/MAX操做或者對於MyISAM存儲引擎優化COUNT(*)操做, 沒必要等到執行階段再進行計算,查詢執行計劃生成的階段即完成優化 8、distinct: 優化distinct操做,在找到第一匹配的元祖後即中止找一樣值的操做 |
1.更改INSERT INTO爲 INSERT DELAYED INTO 更改INSERT INTO爲 INSERT DELAYED INTO,是客戶端提交數據給MySQL,MySQL返回OK狀態給客戶端。而這是並非已經將數據插入表,而是存儲在內存裏面等待排隊。當mysql有空餘時,再插入。 這樣的好處是,提升插入的速度,客戶端不須要等待太長時間。壞處是,不能返回自動遞增的ID,以及系統崩潰時,MySQL尚未來得及插入數據的話,這些數據將會丟失。 經過phpMyAdmin觀測MySQL的進程,提交後,會有一些用戶爲DELAYED,狀態爲Waiting for INSERT的進程。過一會,數據徹底插入後就消失了。 2.優化group by語句 由group by id 改成 group by id order by null 默認狀況下,MySQL 對全部 GROUP BY col1,col2….的字段進行排序。這與在查詢中指定 ORDER BY col1,col2…相似。所以,若是顯式包括一個包含相同的列的 ORDER BY 子句,則對 MySQL 的實際執行性能沒有什麼影響。 若是查詢包括 GROUP BY 但用戶想要避免排序結果的消耗,則能夠指定 ORDER BY NULL禁止排序。 3.優化order by 語句 MySQL 可使用一個索引來知足 ORDER BY 子句,而不須要額外的排序。 WHERE 條件和 ORDER BY 使用相同的索引,而且 ORDER BY 的順序和索引順序相同,而且 ORDER BY 的字段都是升序或者都是降序。 如下狀況不使用索引: 1.order by 字段混合desc和asc. 例如:order by t1 desc, t2 asc; 2.用於查詢行的關鍵字與order by中使用的不一樣。例如:...where t1=a order by t2; 3.對不一樣的關鍵字使用order by. 例如:order by t1,t2; 4.優化嵌套查詢 使用子查詢消除方法。(將子查詢改成join鏈接) Select * from t1 where id not in (select id from t2)改成: Select * from t1 left join t2 on t1.id=t2.id where t2.id is null; 5.優化or條件 對於含有 OR 的查詢子句,若是要利用索引,則 OR 之間的每一個條件列都必須用到索引; 若是沒有索引,則應該考慮增長索引。 6.一些sql提示 1.use index ---指定索引 在查詢語句中表名的後面,添加 USE INDEX 來提供但願 MySQL 去參考的索引列表,就可 以讓 MySQL 再也不考慮其餘可用的索引。 Select * from lbghaha where d=’e’; mysql> select * from lbghaha use index(ind_haha) where d='e'; ---指定索引執行 2.IGNORE INDEX --忽略索引 若是用戶只是單純地想讓 MySQL 忽略一個或者多個索引,則可使用 IGNORE INDEX 做爲 HINT(暗示)。 mysql> select * from lbghaha ignore index(ind_haha) where d='e'; 3.FORCE INDEX 爲強制 MySQL 使用一個特定的索引,可在查詢中使用 FORCE INDEX 做爲 HINT(暗示)。例如, 當不強制使用索引的時候,由於 id 的值都是大於 0 的,所以 MySQL 會默認進行全表掃描, 而不使用索引。 mysql> select * from lbghaha force index(ind_haha) where d='e'; 12.大數據量數據入庫應該如何優化對於數據庫層面如何優化: 優化參數: 1.重建索引 2.trx_commit sync_bin sql_log_bin 和IO有關參數 3.批量提交SQL ,不要 insert commit; insert commit; 而是 for insert(10000) commit; 優化硬件: OLTP環境,能夠購買更好的硬盤來支撐業務,更好的網卡來支撐流量
業務優化 1.多線程處理,使用多線程同時讀寫數據 2.設置隊列,作大量數據的緩衝工做(隊列 內存緩存(redis memcache))
架構優化 1.使用一些mysql的特定的存儲引擎來支撐大壓力的數據入庫 2.或者不用mysql,用一些nosql或者hadoop來支撐
大批量數據入庫方法: 對於 MyISAM 存儲引擎的表: 當用 load 命令導入數據的時候,適當的設置能夠提升導入的速度。 (對innodb無效) Alter table lbg disable keys; ---取消索引 Loading the data ---導入數據 Alter table lbg enable keys; --索引生效 Innodb儲存引擎導入大批量數據快速的方法: (1)由於 InnoDB 類型的表是按照主鍵的順序保存的,因此將導入的數據按照主鍵的順 序排列,能夠有效地提升導入數據的效率。 (2)在導入數據前執行 SET UNIQUE_CHECKS=0,關閉惟一性校驗,在導入結束後執行 SET UNIQUE_CHECKS=1,恢復惟一性校驗,能夠提升導入的效率。 (3)若是應用使用自動提交的方式,建議在導入前執行 SET AUTOCOMMIT=0,關閉自 動提交,導入結束後再執行 SET AUTOCOMMIT=1,打開自動提交,也能夠提升導入的效率。 |