MySQL运维实战 之 PHP访问MySQL你使用对了吗
大家都知道,slow query系統(tǒng)做的好不好,直接決定了解決slow query的效率問(wèn)題
一個(gè)數(shù)據(jù)庫(kù)管理平臺(tái),擁有一個(gè)好的slow query系統(tǒng),基本上就擁有了解鎖性能問(wèn)題的鑰匙
但是今天主要分享的并不是平臺(tái),而是在平臺(tái)中看到的奇葩指數(shù)五顆星的slow issue
好了,關(guān)子賣完了,直接進(jìn)入正題
一、癥狀
一堆如下慢查詢
# User@Host: cra[cra] @ [xx] Id: 3352884621 # Query_time: 0.183673 Lock_time: 0.000000 Rows_sent: 0 Rows_examined: 0 use xx_db; SET timestamp=1549900927; # administrator command: Prepare;# Time: 2019-02-12T00:02:07.516803+08:00 # User@Host: cra[cra] @ [xx] Id: 3351119968 # Query_time: 0.294081 Lock_time: 0.000000 Rows_sent: 0 Rows_examined: 0 SET timestamp=1549900927; # administrator command: Prepare;從我們的監(jiān)控圖上可以看到,每天不定時(shí)間段的slow query 總數(shù)在攀升,但是卻看不到任何query 語(yǔ)句
這是我接觸到的slow query優(yōu)化案例中從來(lái)沒(méi)有過(guò)的情況,比較好奇,也比較興奮,至此決心要好好看看這個(gè)問(wèn)題
二、排查
要解決這個(gè)問(wèn)題,首先想到的是,如何復(fù)現(xiàn)這個(gè)問(wèn)題,如何模擬復(fù)現(xiàn)這個(gè)癥狀
- MySQL客戶端 模擬prepare
結(jié)論是: MySQL client 模擬出來(lái)的prepare 并不是我們期待的,并沒(méi)有得到我們想要的 administrator command: Prepare
- perl 模擬prepare
結(jié)論是:跟MySQL客戶端一樣,同樣是看不到administrator command: Prepare
- php 模擬prepare
- php模擬得到的slow 結(jié)果
結(jié)論: 通過(guò)php代碼,我們成功模擬出了想要的結(jié)果
那順藤摸瓜,抓取下這段時(shí)間有相同session id的整個(gè)sql執(zhí)行過(guò)程
MySQL開(kāi)啟slow=0的抓包模式
可以定位到同一個(gè)session id(3415357118) 的 prepare + execute + close stmt# User@Host: xx_rx[xx_rx] @ [xx.xxx.xxx.132] Id: 3415357118 # Query_time: 0.401453 Lock_time: 0.000000 Rows_sent: 0 Rows_examined: 0 use xx_db; SET timestamp=1550017125; # administrator command: Prepare; # Time: 2019-02-13T08:18:45.624671+08:00 -- # User@Host: xx_rx[xx_rx] @ [xx.xxx.xxx.132] Id: 3415357118 # Query_time: 0.001650 Lock_time: 0.000102 Rows_sent: 0 Rows_examined: 1 use xx_db; SET timestamp=1550017125; update `xx` set `updated_at` = '2019-02-13 08:18:45', `has_sales_office_phone` = 1, `has_presale_permit` = 1 where `id` = 28886; # Time: 2019-02-13T08:18:45.626138+08:00 -- # User@Host: xx_rx[xx_rx] @ [xx.xxx.xxx.132] Id: 3415357118 # Query_time: 0.000029 Lock_time: 0.000000 Rows_sent: 0 Rows_examined: 1 use xx_db; SET timestamp=1550017125; # administrator command: Close stmt; # Time: 2019-02-13T08:18:45.626430+08:00結(jié)論:我們發(fā)現(xiàn),prepare時(shí)間的確很長(zhǎng),但是sql語(yǔ)句卻執(zhí)行的很快,這就很尷尬了
本來(lái)是想通過(guò)抓包,看看是否能夠驗(yàn)證我們的猜想: prepare的語(yǔ)句非常大,或者條件非常復(fù)雜,從而導(dǎo)致prepare在服務(wù)器端很慢
結(jié)果發(fā)現(xiàn)query語(yǔ)句也都非常簡(jiǎn)單
那么既然如此,我們就找了業(yè)務(wù)方,將對(duì)應(yīng)業(yè)務(wù)的prepare方法一起看看
結(jié)果發(fā)現(xiàn),業(yè)務(wù)使用的是php-pdo的方式,所以我們就又有了如下發(fā)現(xiàn)
php-pdo 兩種prepare模式
- http://php.net/manual/zh/pdo.prepare.php
驗(yàn)證兩種prepare模式
- 服務(wù)端prepare模式( ATTR_EMULATE_PREPARES = false)
strace -s200 -f php mysql1.php 跟蹤
大家可以看到這個(gè)模式下,prepare的時(shí)候,是將query+占位符 發(fā)送給服務(wù)端的
- 本地prepare模式 (ATTR_EMULATE_PREPARES = true )
strace -s200 -f php mysql1.php 跟蹤
大家可以看到這個(gè)模式下,prepare的時(shí)候,是不會(huì)將query發(fā)送給服務(wù)端的,只有execute的時(shí)候才會(huì)發(fā)送
跟業(yè)務(wù)方確認(rèn)后,他們使用的是后者,也就是修改了默認(rèn)值,他們?cè)臼窍胩嵘龜?shù)據(jù)庫(kù)的性能,因?yàn)轭A(yù)處理后只需要傳參數(shù)就好了
但是對(duì)于我們的業(yè)務(wù)場(chǎng)景并不適合,我們的場(chǎng)景是頻繁打開(kāi)關(guān)閉連接,也就是預(yù)處理基本就用不到
另外文檔上面也明確指出prepared statements 性能會(huì)不好
調(diào)整和驗(yàn)證
如何驗(yàn)證業(yè)務(wù)方是否將prepare修改為local了呢?
dba:(none)> show global status like 'Com_stmt_prepare'; +------------------+-----------+ | Variable_name | Value | +------------------+-----------+ | Com_stmt_prepare | 716836596 | +------------------+-----------+ 1 row in set (0.00 sec)通過(guò)觀察,發(fā)現(xiàn)這個(gè)值沒(méi)有變化,說(shuō)明調(diào)整已經(jīng)生效
總結(jié)
- prepare的優(yōu)點(diǎn)
- prepare的缺點(diǎn)
- 建議
原文鏈接
本文為云棲社區(qū)原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載。
總結(jié)
以上是生活随笔為你收集整理的MySQL运维实战 之 PHP访问MySQL你使用对了吗的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 云栖专辑 | 阿里开发者们的第4个感悟:
- 下一篇: MSSQL实践-数据库备份加密