一條sql語句輸入到mysql伺服器後,一般要經曆:詞法文法解析(parse),優化(optimize),生成執行計劃(plan)和執行(execute)的過程。詞法文法分析,優化以及生成執行計劃,這三個階段的主要輸出是sql語句的執行計劃(plan),當sql語句存在多種執行計劃的時候,優化器會從這許多的執行計劃中挑選出一個它認為最優的(通常是占用系統資源最少的,包括cpu以及io等)作為最終的執行計劃供執行器執行。生成執行計劃的過程會消耗較多的時間,特别是存在許多可選的執行計劃時。如果在一條sql語句執行的過程中将該語句對應的最終執行計劃進行緩存,當相似的語句再次被輸入伺服器時,就可以直接使用已緩存的執行計劃,進而跳過sql語句生成執行計劃的整個過程,進而可以提高語句的執行速度。
apsaradb mysql 執行計劃緩存目前隻支援select操作的語句(以後會支援其他dml操作)。在相似的sql語句大量重複出現(這裡“相似”的sql語句指的是sql語句中除了常量有所不同外,其他都必須相同)時,使用執行計劃緩存可以極大的節省語句的執行時間。同時,使用執行計劃緩存會帶來額外的記憶體開銷,是以建議在記憶體充裕的情況下使用該功能。
說明:
圖1表示的是apsaradb mysql一條sql語句輸入mysql伺服器的執行過程。
圖2表示的是目前apsaradb mysql plan cache的架構圖。
如圖2所示,plan cache包含了如下幾種資料結構:
1. execute_plan_cache_manager: 對整個plan cache進行管理,負責提供接口供server其他子產品調用。
2. execute_plan_cache_partition(圖示中的partitionx): 為了減少“鎖“對整個plan cache的增删改操作引發性能方面的影響,我們将plan cache 劃分為多個partition,對于每條符合plan cache條件的sql語句隻對其對應的partition進行上“鎖”。
3. execute_plan_cache(圖示中的planx):實際用來存儲plan恢複所需的所有資訊。
rds_enable_exec_plan_cache
範圍
global
類型
bool
功能
a) on 打開plan cache功能。b) off 關閉plan cache功能,清空plan cache(預設)。
rds_max_digest_length
long
a) 設定sql語句中常量替換後的的長度,設定範圍是(128 ~ 1m)。b) 預設值是4k。
c) 如果sql語句長度大于該值,query的plan不會被緩存。
rds_exec_plan_hash_parititions
global readonly
ulong
plan cache manager裡面可以有多少個partition。預設值是cache_manager_partitions(8)
rds_max_exec_plan_caches
a) plan cache裡面可以定義多少條緩存的plan記錄數。b) 防止plan cache skew發生性能問題。
c) 如果太大失效性能會有影響。d) 預設值是max_plan_caches(1024)
備注
如果plan cache中配置設定到某個partition中的記錄數超過了rds_max_exec_plan_caches的平均數,
即rds_max_exec_plan_caches / rds_exec_plan_hash_parititions,
plan cache将利用lru對存在的執行計劃記錄進行淘汰。
rds_max_plan_cache_mem_size
a) 設定plan cache的大小,範圍是(0 ~ +∞)。預設值1m。
如果plan cache中配置設定到某個partition中的記錄所使用的記憶體超過了rds_max_plan_cache_mem_size的平均數,
即rds_max_plan_cache_mem_size / rds_exec_plan_hash_parititions,
支援所有存儲引擎。
不支援update,insert,delete以及ddl。
不支援union,intersect, minus。
不支援explain。
const plan不支援。
系統表查詢不支援。
支援所有select 語句,除下面列出的特殊情況
多表連接配接不支援。
包含subquery或者view的不支援。
不支援sp或者udf。
plan cache中對于依賴于某個表的所有執行計劃記錄,如果表結構發生了修改或者表被drop掉,相關的記錄都将被失效;
如果關閉plan cache功能,即設定rds_enable_exec_plan_cache為off,所有的記錄都将被失效;
可以使用alter table table_name drop cached plan語句将于該表相關的執行計劃記錄失效掉;
no_plan_cache:使用該hint,可以使目前sql語句忽略使用plan cache中緩存的執行計劃,同時plan cache也不會緩存目前sql語句的執行計劃。
force_update_plan_cache:使用該hint,如果plan cache中存在目前sql語句相關的執行計劃記錄,plan cache将強制更新該條sql對應的執行計劃緩沖記錄。
由于目前的plan cache沒有考慮統計資訊變化以及調優過程中使用的強制變更執行計劃的選項,是以如果使用plan cache中緩沖的執行計劃效率比較低,可以通過使用hint來更新plan cache中的記錄。
直接檢視執行計劃緩存。
使用optimizer_trace來檢視目前的sql語句是否使用了plan cache。
檢視目前的plan cache的執行狀态。
execute_plan_cache_hits
顯示目前session,執行的sql語句命中plan cache的條數。
execute_plan_cache_misses
顯示目前session,執行的sql語句未命中plan cache的條數。
execute_plan_cache_records
目前plan cache中存在的與目前session相關的執行計劃緩存記錄數。
execute_plan_cache_total_hits
顯示所有session,執行的sql語句命中plan cache的條數。
execute_plan_cache_total_used_memory
整個plan cache所使用的記憶體大小。
execute_plan_cache_used_memory
目前session相關的plan cache所使用的記憶體大小。
execute_plan_total_cache_records
整個plan cache緩存的執行計劃記錄數。
測試環境:
hw:64bits,32 cores- 64 processors,2.5g hz;記憶體:500g; ssd。
os: centos
測試工具:修改後的sysbench
測試workload:2,4,8,16…1024個sessions。
測試包括ro,rw。
資料集: 100,000行記錄。
測試效果:
圖3是打開和關閉plan cache,對于read only sysbench的測試性能圖,可以看到在plan cache大小不同對于性能的提升也有差異。如果plan cache配置設定記憶體太小,會頻繁進行lru淘汰,導緻性能受到影響。但如果plan cache配置設定的記憶體足夠大,我們可以看到理想狀态下,plan cache可以提升5x左右。
圖4是打開和關閉plan cache,對于read/write sysbench的測試性能圖,可以看到打開plan cache對于write方面的性能幾乎沒有影響。
為了能夠盡量的減少加鎖對并發查詢性能的影響,我們的設計盡可能的減少對鎖的依賴。是以我們對于plan_cache_manager這樣的全局管理對象采取了lock free,并未引入任何rw lock來控制并發。而是對plan_cache_manager下面的每一個partition使用了rw lock。 通過将查詢分散到多個partition中有效的減少了讀寫plan cache的加鎖時間。對于寫入某個partition中的執行計劃我們首先需要對partition加w-lock;而對于從plan cache中的某個partition擷取執行計劃記錄,我們會使用r-lock來控制并發。
如果目前使用者頻繁使用相似的query進行查詢,plan cache可以有效的減少query的優化時間,進而提升query的執行性能。目前plan cache是我們開發的第一個版本,隻是針對我們線上的場景進行優化,很多場景還不支援。希望在未來的時間裡可以完善plan cache,提供更多的場景支援。