針對原生MySQL Query Cache的不足,阿里云進行重新設(shè)計和全新實現(xiàn),推出Fast Query Cache,能夠有效提高數(shù)據(jù)庫查詢性能。

前提條件

背景信息

查詢緩存(Query Cache)是為了提高查詢性能而實現(xiàn)的一種緩存策略,其基本思想是:對于每個符合條件的查詢語句,直接對結(jié)果集進行緩存,當下次查詢命中時,直接從緩存中取出對應的結(jié)果集返回,不需要經(jīng)歷SQL的分析、優(yōu)化、執(zhí)行等復雜過程,通過節(jié)約CPU資源來達到查詢加速的目標,是一項非常實用的技術(shù)。

MySQL原生Query Cache在設(shè)計和實現(xiàn)上存在著較多嚴重問題:

  • 并發(fā)處理較差,在多核情況下,可能并發(fā)越高性能降低越嚴重。
  • 內(nèi)存管理較差,內(nèi)存利用率低并且回收不及時,造成內(nèi)存浪費。
  • 當緩存命中率較低時,性能無提升甚至會出現(xiàn)嚴重降低。

由于以上問題,MySQL原生Query Cache沒有得到廣泛應用,在最新版的MySQL 8.0中,取消此功能。阿里云數(shù)據(jù)庫團隊對Query Cache進行重新設(shè)計和全新實現(xiàn),解決了以上幾個主要問題:

  • 優(yōu)化并發(fā)控制

    取消全局鎖同步機制,采用無鎖機制,重新設(shè)計并發(fā)場景下的同步問題,能夠充分利用多核的處理能力,保證高并發(fā)場景下的性能。

  • 優(yōu)化內(nèi)存管理

    取消內(nèi)存預分配機制,采用更加靈活的動態(tài)內(nèi)存分配機制,及時回收無效的內(nèi)存,保證內(nèi)存的真實利用率。

  • 優(yōu)化緩存機制

    動態(tài)檢測緩存利用率,實時調(diào)整緩存策略,解決命中率偏低或讀寫混合等場景下的性能降低問題。

相比原生Query Cache,F(xiàn)ast Query Cache可以在不同的業(yè)務場景中放心開啟,提高查詢性能。

使用Fast Query Cache

您可以在RDS控制臺設(shè)置參數(shù)query_cache_typequery_cache_size使用Fast Query Cache。

參數(shù) 說明
query_cache_type Fast Query Cache功能開關(guān),取值:
  • 0:默認值,禁用Fast Query Cache。
  • 1:使用Fast Query Cache,但可通過SQL_NO_CACHE關(guān)鍵字跳過緩存。
  • 2:不啟用Fast Query Cache,但可通過SQL_CACHE關(guān)鍵字對特定語句使用緩存。
query_cache_size Fast Query Cache使用的內(nèi)存大小,取值范圍:0~10485760000,需要為1024的整數(shù)倍。單位:Byte。

由于Fast Query Cache功能需要占用額外的內(nèi)存空間,所以建議使用Fast Query Cache功能時同步修改參數(shù)innodb_buffer_pool_size的大小,推薦的修改步驟如下:

  1. 修改innodb_buffer_pool_size為原先的90%,分出10%的空間給query_cache_size。例如原先為{DBInstanceClassMemory*7/10},需要改為{DBInstanceClassMemory*63/100}。具體操作,請參見調(diào)整實例Buffer Pool大小。
  2. 修改參數(shù)query_cache_size。具體操作,請參見設(shè)置實例參數(shù)
    • 若能夠評估結(jié)果集大小,query_cache_size可以設(shè)置為20% * 結(jié)果集大小
    • 若無法準確評估結(jié)果集大小,query_cache_size可以設(shè)置為10% * innodb_buffer_pool_size。
    說明 如果變更實例規(guī)格,參數(shù)query_cache_size的值不會隨實例規(guī)格變化,請及時修改此參數(shù)值。
  3. 修改參數(shù)query_cache_type1,開啟Fast Query Cache功能。具體操作,請參見設(shè)置實例參數(shù)

性能比較

在相同場景下,分別測試QC-OFF(關(guān)閉Query Cache)、MySQL-QC(開啟MySQL原生Query Cache)和Fast-QC(開啟Fast Query Cache)的QPS。

  • 測試環(huán)境:4核8GB 獨享型實例
  • 測試工具:Sysbench
  • 數(shù)據(jù)量:250MB(25張表,每張表40000條記錄)
  • 場景1:全部命中(只讀)

    測試場景為Sysbench oltp_point_select,用例中僅包括主鍵上的點查(point select),將Query Cache設(shè)為512MB,內(nèi)存大于測試數(shù)據(jù)量,緩存可以全部命中,主要關(guān)注不同并發(fā)下的性能提升效果。

    表 1. 全部命中(只讀)QPS
    并發(fā)數(shù) QC-OFF MySQL-QC(相比QC-OFF提升) Fast-QC(相比QC-OFF提升)
    1 8093 8771(8.38%) 9261(14.43%)
    8 62262 65686(5.50%) 75313(20.96%)
    16 97083 73027(-24.78%) 139323(43.51%)
    32 97337 60567(-37.78%) 200978(106.48%)
    64 106283 60216(-43.34%) 221659(108.56%)
    128 107781 62844(-41.69%) 231409(114.70%)
    256 106694 63832(-40.17%) 222187(108.25%)
    512 101733 64866(-36.24%) 203789(100.32%)
    1024 89548 62291(-30.44%) 203542(127.30%)
    全部命中
    說明 測試結(jié)果顯示,在較高并發(fā)的場景下,MySQL原生Query Cache并發(fā)處理性能出現(xiàn)較大幅度的降低,F(xiàn)ast Query Cache在各個并發(fā)場景下無性能降低,最高時能夠提高一倍的QPS。
  • 場景2:高命中率(只讀)

    測試場景為Sysbench oltp_read_only,用例中包含返回多條記錄的范圍查詢,將Query Cache設(shè)為512MB,內(nèi)存才相對比較充足,命中率可以達到80%以上,這時主要關(guān)注不同并發(fā)下的性能提升效果。

    表 2. 高命中率(只讀)QPS
    并發(fā)數(shù) QC-OFF MySQL-QC(相比QC-OFF提升) Fast-QC(相比QC-OFF提升)
    1 5099 6467(26.83%) 7022(37.71%)
    8 28782 28651(-0.46%) 45017(56.41%)
    16 35333 31099(-11.98%) 66770(88.97%)
    32 34864 27610(-20.81%) 67623(93.96%)
    64 35503 27518(-22.49%) 75981(114.01%)
    128 35744 27733(-22.41%) 80396(124.92%)
    256 35685 27738(-22.27%) 80925(126.78%)
    512 35308 27398(-22.40%) 79323(124.66%)
    1024 34044 26861(-22.10%) 75742(122.48%)
    高命中率
    說明 測試結(jié)果顯示,隨著并發(fā)數(shù)的增加,MySQL原生Query Cache的性能出現(xiàn)明顯的降低,F(xiàn)ast Query Cache的性能則會不斷提升,最高時能夠提高一倍多的QPS。
  • 場景3:低命中率(只讀)

    測試場景為Sysbench oltp_read_only,用例中包含返回多條記錄的范圍查詢,將Query Cache設(shè)為16MB,內(nèi)存明顯嚴重不足,緩存命中率只有10%左右,內(nèi)存不足時會涉及緩存項的大量淘汰,影響性能,這時主要關(guān)注不同并發(fā)下的性能降低程度。

    表 3. 低命中率(只讀)QPS
    并發(fā)數(shù) QC-OFF MySQL-QC(相比QC-OFF提升) Fast-QC(相比QC-OFF提升)
    1 5004 4727(-5.54%) 5199(3.90%)
    8 28795 22542(-21.72%) 28578(-0.75%)
    16 35455 24064(-32.13%) 35682(0.64%)
    32 34526 21330(-38.22%) 35871(3.90%)
    64 35514 19791(-44.27%) 36051(1.51%)
    128 35983 19519(-45.75%) 36253(0.75%)
    256 35695 19168(-46.30%) 36337(1.80%)
    512 35182 18420(-47.64%) 35972(2.25%)
    1024 33915 20168(-40.53%) 34546(1.86%)
    低命中率
    說明 測試結(jié)果顯示,MySQL原生Query Cache的性能降低明顯,最多出現(xiàn)了接近50%的性能損失,F(xiàn)ast Query Cache優(yōu)化了低命中率場景,幾乎不會帶來任何額外的性能損失。
  • 場景4:讀寫混合

    測試場景為Sysbench oltp_read_write,每個事務中都有對表的更新操作,可以認為緩存基本處于失效狀態(tài),頻繁的更新操作涉及緩存的主動淘汰,理論上會比較影響性能,這時主要關(guān)注不同并發(fā)下的性能衰減程度。

    表 4. 讀寫混合QPS
    并發(fā)數(shù) QC-OFF Fast-QC(相比QC-OFF提升)
    1 4152 4098(-1.30%)
    8 21359 21195(-0.77%)
    16 26020 25548(-1.81%)
    32 27595 26996(-2.17%)
    64 29229 28733(-1.70%)
    128 29265 28828(-1.49%)
    256 29911 29616(-0.99%)
    512 29148 28816(-1.14%)
    1024 29204 28824(-1.30%)
    讀寫混合
    說明 測試結(jié)果顯示,F(xiàn)ast Query Cache在讀寫混合場景下不會出現(xiàn)過多的性能降低,整體性能影響很小。

實踐指南

在緩存數(shù)據(jù)集大小明確的情況下,例如使用SQL_CACHE關(guān)鍵字對指定表開啟Query Cache,可以參照前面的測試進行性能評估。接下來將對Fast Query Cache的使用作一些補充說明。

  • 適用場景指南
    • Fast Query Cache主要目的是提高讀操作性能,建議在讀多寫少的場景下開啟,或者使用SQL_CACHE關(guān)鍵字針對讀多寫少的表開啟。如果寫多讀少,數(shù)據(jù)的更新非常頻繁,可能會出現(xiàn)很少的性能降低。
    • 開啟Fast Query Cache帶來的性能提升和緩存命中率直接相關(guān)。在全局開啟前建議查看InnoDB Buffer Pool的命中率(命中率 = 1 - Innodb_buffer_pool_reads/Innodb_buffer_pool_read_requests),如果命中率低于80%,則不建議開啟。您也可以通過TABLE_STATISTICS表查看表級別的讀寫比,對讀寫比高的表通過SQL_CACHE關(guān)鍵字顯式開啟Fast Query Cache。查詢TABLE_STATISTICS表請參見Performance Insight。
  • 緩存使用方式(query_cache_type

    query_cache_type參數(shù)支持會話級修改,用戶可以根據(jù)真實業(yè)務場景進行靈活設(shè)置,請參見以下建議:

    • 對于更新頻繁、寫多讀少等不適合Query Cache的場景,應將query_cache_type全局設(shè)置為0。
    • 對于數(shù)據(jù)量較小、訪問模式比較固定、命中率較高的場景,可以將query_cache_type全局設(shè)置為1。
    • 對于數(shù)據(jù)量較大、訪問模式不固定、命中率無法保障的場景,可將query_cache_type設(shè)置為2,僅對指定的語句,通過SQL_CACHE關(guān)鍵字使用Fast Query Cache。
  • 緩存大?。?span id="z68uejxpaoma" class="ph uicontrol" id="uicontrol-hjz-fk6-ics">query_cache_size)設(shè)置

    query_cache_size和SQL息息相關(guān),如果緩存中有返回多條記錄的查詢,緩存可能需要是數(shù)據(jù)量的數(shù)倍。如果SQL中不包含范圍查詢,可以參見以下測試來評估數(shù)據(jù)量和query_cache_size的關(guān)系。

    • 測試環(huán)境:4核8GB獨享型實例(innodb_buffer_pool_size=6GB)
    • 測試工具:Sysbench
    • 數(shù)據(jù)量:10GB(100張表,每張表400000條記錄)

    測試場景為Sysbench oltp_point_select、64并發(fā)、Special分布(20%熱點)。測試不同query_cache_size大小對于性能的影響。對應上述的數(shù)據(jù)量,全量結(jié)果集的真實大小為2.5GB。

    表 5. 不同緩存QPS
    query_cache_size(MB) QC-OFF Fast-QC命中率 Fast-QC(相比QC-OFF提升)
    64 98236 22% 99440(1.23%)
    128 98236 45% 114155(16.21%)
    256 98236 72% 140668(43.19%)
    512 98236 82% 151260(53.98%)
    1024 98236 84% 153866(56.63%)
    2048 98236 87% 159597(62.46%)
    4096 98236 92% 169412(72.45%)

    Fast Query Cache在不同query_cache_size的設(shè)置下都不會引起性能退化,對于主鍵查詢操作,在不同緩存命中率下都有性能提升,達到90%以上時,提升效果比較明顯;對于范圍查詢或帶Order By的排序語句,緩存命中率低于90%時,也能節(jié)約大量的CPU,帶來較大的性能提升。