查詢?cè)诿總€(gè) MySQL 數(shù)據(jù)庫(kù)管理員甚至精通數(shù)據(jù)庫(kù)的開(kāi)發(fā)人員的生活中無(wú)處不在。正如我們?cè)谥暗囊恍┎┛臀恼轮幸呀?jīng)指出的那樣,查詢只是由較小任務(wù)組成的任務(wù)。為了優(yōu)化它們的性能,我們應(yīng)該讓那些較小的任務(wù)執(zhí)行得更快或者根本不執(zhí)行。首先,我們必須檢查 MySQL 如何執(zhí)行查詢。
什么是查詢緩存?
MySQL 查詢緩存雖然在 MySQL 5.7 中被棄用(并在 8.0 中刪除),但存儲(chǔ)以前在內(nèi)存中運(yùn)行的語(yǔ)句:換句話說(shuō),查詢緩存通常將SELECT語(yǔ)句存儲(chǔ)在數(shù)據(jù)庫(kù)的內(nèi)存中。因此,如果我們運(yùn)行一個(gè)查詢,然后在一段時(shí)間后再次運(yùn)行完全相同的查詢,結(jié)果將更快地返回,因?yàn)樗鼈儗膬?nèi)存而不是從磁盤中檢索。
查詢緩存緩存查詢和結(jié)果集。因此,當(dāng)我們運(yùn)行相同的查詢時(shí),查詢緩存的結(jié)果會(huì)立即返回。查詢緩存大小可以通過(guò)設(shè)置query_cache_size系統(tǒng)變量來(lái)控制,但這里有一個(gè)警告:如果您希望查詢使用查詢緩存,它們必須,必須,必須相同,逐字節(jié)。這意味著即使您認(rèn)為這兩個(gè)查詢應(yīng)該以完全相同的方式緩存:
SELECT * FROM demo_table WHERE column = 'Demo';
select * from demo_table where column = 'Demo';
事實(shí)上,他們不是。它們不是因?yàn)?MySQL 查詢緩存要求其所有查詢都相同,并且即使它們相差一個(gè)字節(jié)也不會(huì)返回任何結(jié)果。
所以,總結(jié)一下,當(dāng) MySQL 執(zhí)行語(yǔ)句時(shí),它做的第一件事就是檢查是否啟用了查詢緩存(如果需要復(fù)習(xí),請(qǐng)回到我們上一篇關(guān)于慢速 MySQL 查詢的博客文章。)如果查詢緩存啟用后,MySQL 將首先檢查與該查詢的任何相關(guān)匹配項(xiàng);如果沒(méi)有匹配項(xiàng),MySQL 將繼續(xù)下一步。但是,如果存在相同的匹配項(xiàng),MySQL 將從其查詢緩存中返回結(jié)果。
MySQL內(nèi)部的查詢緩存
在此之前返回比賽,MySQL的查詢緩存要求MySQL的確認(rèn):d OES該用戶有必要的權(quán)限才能完成這樣的動(dòng)作?我應(yīng)該拒絕執(zhí)行查詢嗎?
以下是 MySQL 檢查的權(quán)限列表:
特權(quán) | 簡(jiǎn)要說(shuō)明 |
---|---|
ALL | 賦予特定 MySQL 用戶所有權(quán)限。 |
SELECT | 授予特定 MySQL 用戶從指定數(shù)據(jù)庫(kù)中選擇行的權(quán)限。 |
UPDATE | 授予特定 MySQL 用戶更新指定表中現(xiàn)有行的權(quán)限。 |
SHOW DATABASES | 使特定 MySQL 用戶能夠獲取存在于一個(gè)特定 MySQL 實(shí)例中的所有 MySQL 數(shù)據(jù)庫(kù)的列表。 |
USAGE | 賦予用戶僅使用 MySQL 的權(quán)力,這意味著用戶不能在其中運(yùn)行任何查詢。本質(zhì)上是無(wú)特權(quán)的同義詞。 |
有更多的特權(quán),但你明白了。權(quán)限對(duì)于查詢緩存很重要,因?yàn)?MySQL 還將與表相關(guān)的信息與緩存查詢一起存儲(chǔ)。權(quán)限也很重要,因?yàn)樗?MySQL 結(jié)果檢查過(guò)程的第一階段之一。這是一切的工作原理:
優(yōu)先識(shí)別 | MYSQL 狀態(tài) | 解釋 |
---|---|---|
1 | MySQL 正在檢查查詢緩存中的權(quán)限。 | 首先,MySQL 檢查特定用戶是否有權(quán)訪問(wèn)特定結(jié)果。 |
2 | MySQL 正在檢查查詢本身的查詢緩存。 | 接下來(lái),MySQL 開(kāi)始檢查查詢緩存中是否存在相同的查詢。如果匹配,MySQL 返回;如果沒(méi)有,MySQL 繼續(xù)下一步。 |
3 | MySQL 將查詢緩存中的條目標(biāo)記為無(wú)效。 | 隨著表的變化,查詢緩存需要更新。所以在這一步中,MySQL 決定將查詢緩存中的條目標(biāo)記為無(wú)效。 |
4 | 發(fā)送結(jié)果。 | MySQL 發(fā)送緩存的結(jié)果并顯示它。 |
5 | 將結(jié)果存儲(chǔ)在緩存中。 | MySQL 將查詢結(jié)果保存在查詢緩存中。 |
6 | 查詢緩存被鎖定。 | 緩存過(guò)程現(xiàn)在結(jié)束——MySQL 鎖定查詢緩存。 |
“MySql沒(méi)有緩存!”:要看查詢緩存是否損壞?
當(dāng)使用函數(shù)或分區(qū)時(shí),如果我們?cè)诓樵冎惺褂萌魏巫兞浚樵兙彺嬉矊o(wú)效。例如,如果我們正在處理大數(shù)據(jù),并且我們使用SELECT ... INTO OUTFILE將大數(shù)據(jù)集加載到 MySQL 中,則結(jié)果同樣不會(huì)被緩存。通常,查詢緩存SELECT ... [LOCK | FOR | INTO]在使用類似查詢時(shí)不起作用,如果我們正在檢查具有NULL值的列中的AUTO_INCREMENT值,則查詢緩存也無(wú)法使用,這意味著如果我們有一個(gè)increment帶有 的列AUTO_INCREMENT,并且我們運(yùn)行這樣的查詢所以:
SELECT * FROM demo_table WHERE increment IS NULL;
查詢緩存也不會(huì)生效。
所有這些功能可能會(huì)讓你們中的一些人大喊“它不起作用!” - 你是對(duì)的。查詢緩存并不總是有效:與 MySQL 中的所有內(nèi)容一樣,它也有局限性。除了上述那些,當(dāng)語(yǔ)句生成警告或語(yǔ)句在帶有TEMPORARY存儲(chǔ)引擎的表上運(yùn)行時(shí)以及在其他一些極端情況下,它拒絕工作。每次有人向表寫入任何內(nèi)容時(shí),查詢緩存也會(huì)清空。
查詢緩存的功能也取決于query_cache_size參數(shù)。此參數(shù)越大越好,但請(qǐng)注意,此參數(shù)在很大程度上取決于您的內(nèi)存。請(qǐng)記住,查詢緩存的基本結(jié)構(gòu)默認(rèn)至少需要 40kB 的存儲(chǔ)空間,其默認(rèn)值可能在 1MB 到 16MB 之間。但是,如果您的數(shù)據(jù)庫(kù)非常忙于讀取數(shù)據(jù),則更大的值可能有助于找到最佳解決方案,您必須再次進(jìn)行試驗(yàn)。
您還可以通過(guò)運(yùn)行該RESET QUERY CACHE語(yǔ)句來(lái)刪除查詢緩存中的所有內(nèi)容。如果您使用類似 的語(yǔ)句FLUSH TABLES,所有值也將從查詢緩存中刪除。
MySQL 甚至允許您通過(guò)運(yùn)行查詢來(lái)查看查詢緩存中存儲(chǔ)了多少查詢:
SHOW STATUS LIKE 'Qcache_queries_in_cache%';
您會(huì)得到如下所示的結(jié)果:
MySQL:
+-------------------------+--------+
| Variable_name | Value |
+-------------------------+--------+
| Qcache_queries_in_cache | 1 |
+-------------------------+--------+
在這種情況下,我們可以看到我們的查詢緩存當(dāng)前緩存了一個(gè)結(jié)果。執(zhí)行類似的語(yǔ)句FLUSH TABLES,所有值都將消失。
總結(jié)
在 MySQL 中,查詢緩存是一個(gè)非常強(qiáng)大的野獸。它通常能夠存儲(chǔ)各種各樣的值并從內(nèi)存中返回它們,而不是從磁盤中返回它們,以加快查詢執(zhí)行時(shí)間。然而,它并非沒(méi)有缺陷。查詢緩存有一些限制,但如果您知道自己在做什么,應(yīng)該沒(méi)問(wèn)題。
查詢緩存對(duì)于SELECT查詢最有用的。