mysql查詢快取的實現 mysql的查詢快取

2021-10-19 19:39:52 字數 3466 閱讀 2652

工作方式要點

1. 以查詢語句作為key, 以結果集作為值的放key => value方式快取

2. 直接以查詢語句作為key , 不會對查詢語句做任何變換, 比如中間的注釋, 不同的大小寫都會導致有不同的key, 比如

select f_a from t_b; 和

select f_a from t_b;是不同的快取key

3. 不快取語句中包含有非確定性函式的查詢的結果集合, 比如current_user(), now()等, 對於這類查詢, 儘管結果不會被快取 ,但是當查詢緩衝功能開啟時, 每次查詢時, 還是會去查詢快取區先檢視的; 對於這種情況,

用具體的值代替, 比如

date_sub(current_date, interval 1 day)

date_sub('2007-07-14', interval 1 day)

4. 當某個表被修改了, 會導致與該錶有關的所有查詢快取都無效

5. 超過   位元組的結果集部會被快取

用快取會有哪些效率損失

1. 所有的查詢請求執行前會去緩衝區裡面看一下是否有匹配項

2. 當乙個查詢時可以快取的而沒有被快取,那麼查詢執行完成後, 會把結果放到快取中

3. 當某個表被修改後, 與它其有關的所有快取項都將失效

4. 對於innodb來說, 如果某個表在某個事務中被修改了, 那麼不但與該錶相關的所有快取項需要變成無效, 而且在事務提交前, 與該錶有關的查詢都不能快取

記憶體管理

1. 40kb左右的記憶體用來維護一些資料結構, 其次就是結果集緩池了; 快取池是一次性從系統分配好的, 因此每次分配塊時不會都去呼叫系統記憶體分配呼叫函式

2. 維護的資料有: 表和快取結果集的對應關係, 快取結果集, 查詢語句集合等

3. 快取池以(可變大小的)塊為單位使用, 每次申請時,從快取池裡分配能夠滿足要求的盡可能小(不能小於query_cache_min_res_unit)的記憶體塊; 由於分配的記憶體大小不大可能與資料塊大小一樣, 因此有一些小的記憶體塊被空置;

時間一長, 就會出現記憶體碎片 (這個和作業系統上的最佳記憶體分配方式類似)

什麼樣快取命中率好

用快取的效率損失前面說過了, 不用快取的話, 意味著每次都需要重新產生結果集; 但到底是那個效率更好, 這個從理論上講是不容易做出判斷的, 而且還受到一些外部因素的影響, 比如快取能減少查詢的時間,

但是不能減少傳送資料集的時間, 如果瓶頸在於傳送資料的速度的話, 快取的效果就看不到了。 另外, 有時候高的命中率也不能代筆高的效率, 比如有兩個表, t_a有10次查詢, 都命中了, 那麼命中率是100%;

另乙個表有1000000次更新而沒有查詢, 那麼這寫更新的開銷可能比這個100%的命中率帶來的好處要多。

理論上見, 快取最理想用在哪些產生資料集資源要求多, 而儲存資源要求少的查詢;比如count(), sum等, 當然,前提是表資料不是頻繁變化。

乙個判斷快取效果的方式是看快取命中率 qcache_hits /  (qcache_hits+com_select), 但這個值多少合適就需要根據實際情況而定了, 這個和所快取的查詢有關, 也和所快取的查詢的結果集有關。也和伺服器所處的階段有關,

比如預熱階段的命中率比較低是正常的。 當然, 快取命中率低的一些原因有:

1. 查詢是不能被快取的, 比如有crrrent_date的函式

2. 總是新的查詢語句, 比如預熱階段

3. 所快取語句涉及到的表被頻繁更新, 通過com_update, com_delete等來檢視

4. 業務本省就沒有多少重複查詢

5. 快取池的大小可能不夠, 導致頻繁的有查詢結果集被清理掉或者空間不夠而無法快取, 通過qcache_lowmem_prunes可以看由於記憶體較少從快取刪除的查詢數量

6. 快取池碎片化過於嚴重

另外, 要注意一種情況, 就是一條記錄被查詢時, 如果沒有命中 ,那麼系統會快取這條記錄 ,但是馬上被修改了, 從而導致該記錄立刻被失效掉, 然後, 又被查詢,這樣導致很多無效的快取; 從而導致效率降低, 這種情況下,

com_select 和com_insert相差不大。

碎片問題

碎片隨快取的命中率影響比較大 ,通過一些引數可以大體估計一下, 從qcache_free_blocks可以知道大概有多少的空閒塊, 如果這個值與qcache_total_blocks/2比較接近的話 ,就意味著碎片化比較嚴重了, 這個可以這麼理解, 當

產生碎片時, 通常是乙個分配的記憶體塊沒有用完而產生而而導致的, 這是就是乙個有效塊和乙個空閒塊了, 從而達成1:1的大體比例; 這個時候, 如果qcache_lowmem_prunes還很高的話, 那說明碎片在引起一些問題了。

記憶體塊分配的大小對碎片的產生有著比重要的影響, 如果過大, 導致分配的記憶體塊無法有效的使用, 從而使得碎片增加 ,過小的話, 不但可能導致碎片也會增加, 而且效率會降低, 因為可能在快取乙個結果集的過程中多次分配記憶體塊。 這個時候,

通過變數query_cache_min_res_unit來控制每次分配的記憶體塊的大小, 那麼如何來計算大體值呢, 通過(query_cache_size – qcache_free_memory) / qcache_queries_in_cache 可以計算出快取的結果集的平均大小。 另外, 快取太大的記過集可能得大於失,

因為這可能導致多次的記憶體塊分配, 如果加上快取失效時間短的話, 就更不合算了, 在這種情況下, 考慮通過query_cache_limit來控制那麼太大的結果集的快取。

改善快取的使用

快取的多少對快取效果影響比較大的。 qcache_lowmem_prunes這個狀態引數給出了有多少條目因為記憶體不夠而無法被快取的。如前面提到的, 碎片化可能導致這個問題(這時qcache_free_blocks一般比較多),另外乙個情況就是快取池大小不夠,

這種情況下 ,qcache_free_blocks比較少, 同時qcache_free_memory也不多。

在非啟動預熱階段, 如果碎片化不嚴重 ,qcache_free_blocks和qcache_free_memory也不少 ,qcache_lowmem_prunes也不大 ,而qcache_hits現實命中率還是不高的話, 那要看看是不是業務的庫操作不適合快取, 或者語句不適合快取。

innodb與查詢快取

在mysql4.0以前, 事務裡面是不允許訪問快取的, mysql4.1以後, 可以訪問了, 但是以表為基礎, 根據表的事務id和鎖情況來控制查詢快取的訪問:

1. 當事務的id小於與它相關的表的事務id(innodb的每個表, 在記憶體中有乙個與之相關的事務id)時, 不允許訪問記憶體快取, 比如但事務併發時 ,乙個事物id大的事務提交了資料修改後, 比其事務id小的, 但沒有提交的所有事務都無法訪問快取的結果集

2. 任何有加鎖行為的語句都會導致無法快取, 比如 select.... for update;

設計和編碼時的優化

1. 把大表分成多個小表, 這是因為查詢快取的實效是以表位單位來處理的

2. 批處理多個修改操作比單個修改操作有效, 因為可以減少失效查詢快取的次數, 從而減少開銷

3. 對於寫負荷很大的應用, 可以考慮關閉查詢快取功能

mysql資料快取查詢 Mysql查詢快取

查詢快取 mysql提供了一種快取型別,會快取整個select查詢結果。mysql查詢快取儲存查詢返回的完整結果。當查詢命中該快取,mysql會立即返回結果,跳過了解析 優化和執行階段。以下兩種情況不能被快取 頻繁更新 修改的的表,所有快取資料都會失效,mysql查詢快取會跟蹤查詢中涉及的表,如果這...

mysql 查詢快取

show variables like cache my.cnf設定 mysql慢日誌 mysql有乙個功能就是可以log下來執行的比較慢的sql語句,預設是沒有這個log的,為了開啟這個功能,要修改my.cnf或者在mysql啟動的時候加入一些引數。如果在my.cnf裡面修改,需增加如下幾行 lo...

mysql查詢快取

查詢快取不開啟 r mysql query select username from user where signup date curdate 開啟查詢快取 today date y m d r mysql query select username from user where signup...