MySQL/MariaDB基礎(2)
緩存中的數據是開源形式的,以鍵值對(k/v)的形式存在
key:查詢語句的hash值;
value:查詢語句的查詢結果;
緩存中的數據主要是通過整個查詢語句的hash值的比較,完全相同則命中;這樣通過緩存響應客戶端請求,可以提高檢索效率;當然,也不是所有的查詢數據都可以緩存,那麽哪些數據不能夠緩存呢?
1.要查詢的數據庫中可能包含敏感信息;如MySQL數據庫中的各系統表; 2.在查詢語句中包含有用戶自定義的函數(UDF) 3.存儲函數; 4.用戶自定義變量; 5.對於臨時表發起的查詢請求; 6.包含列級別授權的查詢; 7.有著不確定結果值的mysql的內鍵函數;如:NOW(),CURRENT_DATE(),CURRENT_TIME(),CURRENT_USER(),...
與查詢緩存相關的服務器參數:
MariaDB [hellodb]> show global variables like 'query_cache%'; +------------------------------+---------+ | Variable_name | Value | +------------------------------+---------+ | query_cache_limit | 1048576 | | query_cache_min_res_unit | 4096 | | query_cache_size | 0 | | query_cache_strip_comments | OFF | | query_cache_type | ON | | query_cache_wlock_invalidate| OFF | +------------------------------+---------+
query_cache_limit:能夠緩存查詢結果的最大字節數上限;(單語句結果集的上限)
在使用SELECT查詢語句時,應盡量避免"SELECT *"查詢方式的應用,同時需要WHERE子句或HAVING子句對查詢結果進行優化處理;以使得查詢結果盡可能精確;
對於哪些有著較大的查詢結果集的語句,應該在SELECT中明確顯式的使用SQL_NO_CACHE參數,以避免查詢結果先如緩存再移除緩存;
query_cache_min_res_unit:查詢緩存中,內存塊的最小分配單元;可以比較有效的避免內存碎片;
較大的變量值可能會帶來內存空間浪費;
較小的變量值會減少內存空間浪費,但會導致更加頻繁的內存分配和回收操作;長期下來必然產生內存碎片;
query_cache_size:查詢緩存申請的在內存中的總可用空間;
單位是字節,設定的值必須是1024的整數倍;
query_cache_strip_comments:用於控制是否去掉SQL查詢語句中的註釋部分之後再作為key部分存入查詢緩存;
默認值是"OFF",如果啟用,插入查詢緩存中的查詢語句是不帶有註釋部分信息的
query_cache_type:緩存功能開啟與否的開關;
ON:啟用;僅不緩存"SQL_NO_CACHE"參數的查詢結果;
OFF:停用緩存;
DEMAND:按需緩存;默認不緩存,僅緩存"SQL_CACHE"參數的查詢結果;
query_cache_wlock_invalidate:如果某個連接會話對某表施加了寫鎖,是否依然可以從緩存中查詢並返回查詢結果;
默認值為"OFF",表示可以;
ON,表示不可以;
與查詢緩存相關的服務器參數:
Qcache_free_blocks:表示查詢緩存中目前還剩余多少個blocks;如果該值顯示較大,則說明查詢緩存中內存碎片過多;
Qcache_free_memory:查詢緩存中還空閑的內存空間;
通過此狀態參數可以評估當前系統中的查詢緩存的使用情況;
如果剩余量太小,且剩余塊很多,大量的內存空間均以碎片形式存在;
如果剩余量太小,且剩余塊不多,分配的查詢緩存的內存空間剛好或略有欠缺;
如果剩余量較大,分配的查詢緩存的內存空間太多,應進行相應調整;一旦調整了緩存大小,則其中存放的查詢結果會立即清除;
Qcache_hits:表示查詢緩存中查詢語句的命中次數;數字越大緩存效果越理想;
Qcache_inserts:表示未命中的而後經過處理將查詢結果添加至查詢請求的數量;
數值越大,則證明查詢緩存效果越不理想;
可以通過規範書寫查詢請求的SQL語句減少此類查詢請求的數量;
註意:如果查詢緩存中確實沒有對應查詢語句的查詢緩存,此數值的增加也是正常現象;
Qcache_lowmem_prunes:該參數記錄了有多少條查詢請求是因為內存空間不足而基於LRU算法被移除緩存的;如果該數值過大,則表示分配的內存空間太小;
Qcache_not_cached:取決於query_cache_type變量的設置的作用下,沒有被緩存的查詢請求的數量;
Qcache_queries_in_cache:當前查詢緩存中緩存的查詢請求的結果的數量;
Qcache_total_blocks:當前查詢緩存中總計分配了多少個block;
查詢緩存命中率的計算:Qcache_hits/( Qcache_hits + Qcache_inserts )
註意:如果對表進行了寫操作,例如增刪改等操作,則MySQL會自動將查詢緩存中與該表相關的緩存項全部清除;因此與此表有關的查詢請求必須重新構建緩存內容;
緩存的優化方式:
1.盡可能批量寫入(構建自定義過程;啟用事務),盡量減少多次的單寫入操作; 2.緩存空間不宜設置過大,如果大量緩存同時失效,會使得MySQL的執行引擎壓力劇增,可能會導致服務器假死; 3.必要時,需要使用SQL_CACHE和SQL_NO_CACHE等SELECT語句中的參數來手動控制緩存存入與否; 4.對於密集型寫操作應用場景來說,禁用緩存功能可能提升服務器性能;
接下來做個實例:
1.首先要保證query_cache_type開啟:
2.為緩存空間設置一個大小
3.查詢一下某個數據的數據表;
//在狀態參數中未命中出現一次,因為沒有緩存;並且這次查詢完成後,緩存了一條信息;
4.再次進行與上次查詢一樣的查詢;
//這次hits段命中了一次;你可以多次查詢查看命中次數;
MySQL的索引
那麽是為了什麽而提出的索引呢,即索引的作用是什麽呢:當MySQL中數據過多時,要求檢索的速度也應該高,所以,為了提高檢索速度,提出了索引這一概念;什麽是索引:也就是指定的表中的數據子集;即:將表中某個或某些字段中的數據提取出來,另存為用一個特定數據結構進行組織的數據。
索引有不同類型:FULLTEXT,SPACIAL,B+ TREE,HASH;由於存儲引擎不同,支持的索引的類型也不同:
InnoDB存儲引擎支持:B+ TREE,HASH; MEMORY存儲引擎:顯示的支持HASH索引;
下面大概描述一下不同的索引:
B+ TREE索引:也就是順序存儲,所有的存儲數據都存放在葉節點上,並且每個葉節點都有順序訪問指針,以此指針指向相鄰的葉子節點;
B+ TREE索引使用的場景:
1.全鍵值匹配:精確匹配某個值; select ... where Name='Xu Wenlong' 2.左前綴匹配:值精確到數據起始位置的一部分: select ... where Name like 'G%' 3.區間數據的連續數值匹配,通常用於BETWEEN...AND...環境中: select ... where age between 30 and 50; 4.區間數據的離散值匹配;通常用於IN列表環境或OR列表環境;也是精確值匹配; select ... where StuID IN (1,3,7) 5.精確匹配左列,範圍匹配右側其他列; select ... where StuID > 10 and name like 'a%'; 6.對於覆蓋索引的查詢請求:
不適用的場景:
1.如果查詢條件不是精確從最左側列開始的,索引無效; 對StuID字段做索引,select ... where Name like 'A%' and StuID>10; 2.如果索引了多列,若跳過索引中的某列,索引無效: 對StuID,Name,Age做索引,select ... where StuID>10 and Age>20; 3.如果索引了多列,且在查詢語句中對某個列做範圍匹配,則其右側列不能再使用索引優化查詢; 對StuID,Name,Age做索引,select ... where StuID>10 and Name like 'a%';
HASH索引:基於HASH表實現的索引;非常適用於值的精確匹配的查詢請求;
適用的場景:只支持等值比較查詢:如:=,IN(),<=>(NULL safe equal());
不適用場景:所有的非精確值的比較查詢:
索引的優點:
1.較少需要掃描的數據總量,減少IO次數; 2.腳面對掃描的數據進行再次排序; 3.避免生成和使用臨時表; 4.將隨機IO轉換成順序IO;
定義索引的一般性規則:
1.選擇用於索引的數據類型; 越小的數據類型越適於做索引; 越簡單的數據類型越適於做索引; 盡量避免該字段中出現"NULL"值;如果必須要使用空值;建議使用"0"或一個空的字符串或者某個認可的特殊值來代替"NULL"值; 2.選擇主鍵的類型; 優先選擇整型; ×××數據可以更快速被處理;而且可以使用AUTO_INCREMENT修飾符避免重復數據; 盡量避免使用字符型; 存儲字符型數據需要消耗更多的空間,處理字符型數據需要消耗更多的CPU和內存資源,處理速度較慢;
高性能索引的定義策略:
1.在WHERE子句中以獨立使用某列做判斷條件為最佳,盡量避免該列直接參數運算; select ... where Age+2>10; 2.最左前綴索引:索引應該構建於字段的最左側的一個或連續的多個字符;具體的選擇數量可以通過"索引選擇性"進行評估; 索引選擇性:不重復的索引值和數據表的記錄總數的比值; 3.多列索引的選擇; WHERE條件子句中使用AND運算符連接多個查詢條件;盡量避免使用OR運算符; 如果使用OR運算符,應該基於每個列做單列索引; 4.選擇合適的索引定義次序;選擇性最高的列放在最左側;
EXPLAIN語句
對索引進行分析,查看索引的應用信息;
用法:
EXPLAIN [explain_type] SELECT select_options explain_type: EXTENDED | PARTITIONS
EXTENDED:顯示擴展信息;
PARTITIONS:用於分區表;
下面來上一個例子:
咱們對個字段來做個解釋:
id:當前的查詢語句中,各個SELECT語句的編號;
select_type:查詢類型;
簡單查詢:SIMPLE //即通過交叉連接來查詢;
復雜查詢:
簡單子查詢(用於WHERE子句中的子查詢):SUBQUERY
用於FROM語句中的子查詢;DERIVED
聯合查詢中的第一個查詢:PRIMARY
聯合查詢中其他的查詢:UNION
聯合查詢時生成的臨時表查詢:UNION RESULT
table:當前的查詢語句所針對的表;
type:關聯類型,或稱為訪問類型;也可以理解為MySQL是如何查詢表中的行;
ALL:全表掃描;,MySQL將遍歷全表以找到可以匹配的行; index:全表掃描,與ALL所不同的是index類型只是遍歷索引樹; range:索引範圍掃描,對索引的掃描從某一個點開始,返回匹配某一個值域的行; 通常可以基於指定的索引,WHERE子句使用IN列表、BETWEEN...AND...、或帶有"=",">","<"等的查詢; ref:使用非唯一索引掃描或者使用唯一索引的左前綴掃描;返回匹配某個單獨值的行; eq_ref:類似於ref,區別就是使用唯一索引,對於每一個索引鍵值,表中都只有一條記錄匹配;無論是單表查詢還是多表查詢,都使用主鍵或唯一鍵索引來作為關聯條件; const,system:當MySQL對查詢部分進行優化,並且將優化結果轉換為一個常量,使用const類型; system類型是一個const類型特例,當要查詢的表中只有一行時,使用system類型; NULL:MySQL在優化過程中分解查詢語句,而執行時不用訪問表或索引;
possible_keys:為了執行查詢語句,MySQL可能使用哪個索引在表中查找到記錄;
如果查詢所涉及到的字段上存在索引,則該索引會被列出,但不一定會被查詢使用;
key:顯示MySQL數據庫在查詢過程中,實際使用到的索引;如果查詢過程沒有用到任何索引,則此處顯示為"NULL";
key_len:表示索引中可以被引用的字節數;可以通過該列計算查詢中使用的索引的長度;
註意:key_len顯示的值通常為索引字段的最大可能長度,並不是實際的使用長度;因此key_len是根據表定義時指定的字段長度計算得到的,而並不是在表中通過檢索數據得到的;
ref:在利用key字段所顯示的索引完成查詢操作時所引用的列或常量值;如果都沒有則顯示為"NULL";
rows:表示MySQL根據表統計信息及索引選用的情況,估算的本次檢索所需要去查找到的所有記錄的過程中需要讀取的表的行數;
Extra:額外信息,或稱擴展信息;
Using where:表示MySQL服務器將在存儲引擎檢索後再次進行調校過濾;許多的where條件裏涉及到索引中的列並且當MySQL讀取該索引時,既可以被存儲引擎檢驗; Using index:使用了覆蓋索引進行檢索; Using temporary:在查詢過程中使用了臨時表來存放查詢結果集;常見於排序或分組查詢; Using filesort:MySQL中無法利用索引完成排序操作就稱為"文件排序"; Using join buffer:強調了在獲取連接條件時沒有使用到索引,並且需要連接緩沖區來存儲中間結果。如果出現了該值,需要根據查詢的具體情況適當的添加索引以提示查詢性能; Impossible where:如果該值出現,則意味著where子句沒有發現符合條件的行; Select tables optimized away:該值意味著僅通過使用索引來進行查詢,但是優化器可能從聚合函數的結果中給出一個可行的優化方案; Using sort-union(...) Using union(...) Using intersect(...) 上述情況多出現於在實現查詢的過程中,決定使用不止一個索引時; filtered:從可選的行中再次過濾之後選擇出最終的查詢結果的比值;
EXPLAIN總結:
1.EXPLAIN語句並不會告知關於觸發器、存儲過程相關的信息或用戶自定義函數對查詢的影響情況; 2.EXPLAIN語句不會考慮任何Cache; 3.EXPLAIN語句不會顯示MySQL自身的執行查詢時所作出的優化操作; 4.部分統計信息並不是精確值,而是估算結果; 5.EXPLAIN語句只能分析解釋SELECT語句,其他的暗含SELECT語句的操作;其他的非SELECT操作只有在重寫為SELECT後,才能查看執行計劃
MySQL/MariaDB基礎(2)