天天看點

記一次mysql查詢慢的優化曆程

有一個項目,代稱​

​cc​

​,用了我們公司的産品,單表資料量在200萬左右。在做業務操作的時候,點選一下按鈕,需要等待2~3分鐘。及其難以忍受,特此讓我們修改。

PS:涉及的一些​

​sql​

​指令,簡化了很多,不能暴露線上資訊。

第一反應

當收到這個問題的時候,第一反應就是确定下到底是背景資料查詢慢,還是前端資料渲染慢,亦或者是網慢,那麼如何排查呢?

詢問客戶使用了産品的哪個功能,然後自己模拟一下,并使用F12,追蹤下總的時間,是否如客戶所說的時長;

定位問題

結果,果然,點選一下然後就開始了漫長的等待,竟然真的需要2~3分鐘,完成一個業務流竟然需要10分鐘(該業務流需要多次點選菜單處理資料)。

驗證客戶所說為真。

和網速沒關系;

那麼接下來驗證下是前端還是背景慢;

看下​

​mysql​

​​資料庫的慢​

​sql​

​​記錄,是否存在長時間的​

​sql​

​語句。

如果​

​mysql​

​​沒有配置慢​

​sql​

​記錄,那麼首先我們要進行如下配置:

vim /etc/my.cnf
# 在 [mysqld] 子產品中
slow-query-log=On
slow_query_log_file="/data/mysql/localhost-slow.log"      

配置完畢之後,需要重新開機下​

​mysql​

​服務。

systemctl restart mysqld.service      

而後再次模拟​

​cc​

​​客戶回報慢的地方,運作完畢之後,看下存儲慢​

​sql​

​檔案的地方,裡面是否有資料;

vim /data/mysql/localhost-slow.log      

果然有,而且時間和前端展示的總時間差不太多,說明響應慢的問題,一大半的原因是因為資料庫慢所導緻的。其他的就是前端資料渲染慢+服務中轉+網速問題了。

解決思路

資料庫​

​sql​

​慢的思路:

首先我們需要找到所有的慢​

​sql​

​​,找到之後,第一反應應該是查有沒有配置索引,有沒有添加索引,使用​

​explain + sql​

​ 的方式來檢視,例如:

explain select (*) from ceshi_1;      

在展示的資訊中,各個參數含義如下:

  • id:選擇辨別符
  • select_type:表示查詢的類型
  • table:輸出結果集的表
  • partitions:比對的分區
  • type:表示表的連接配接類型
  • possible_keys:表示查詢時,可能使用的索引
  • key:表示實際使用的索引
  • key_len:索引字段的長度
  • ref:列與索引的比較
  • rows:掃描出的行數(估算的行數)
  • filtered:按表條件過濾的行百分比
  • Extra:執行情況的描述和說明

根據​

​possible_keys​

​​和​

​key​

​即可看到是否配置和使用了索引,如果沒有就添加,如果有就檢查其他問題。

前端慢的思路:

需要看下前端資源是否進行了壓縮傳輸,以及網速問題;

大機率情況下,網速一般是不需要解決的,除非說這個項目是剛上線就特别慢,這種情況才需要解決網速問題,是以我們隻需要看下前端資源是否進行了壓縮傳輸即可。

前端一般使用的是​

​nginx​

​;我們看下是否進行了如下配置:

gzip on;
gzip_buffers 32 4k;
gzip_comp_level 2;
gzip_min_length 300k;
gzip_types text/plain  application/x-javascript application/javascript application/xml text/css text/javascript image/jpeg image/gif image/png;
gzip_disable "MSIE [1-6]\.";
gzip_vary on;      

以上内容,應該配置在​

​nginx​

​​中的​

​conf/nginx.conf​

​​檔案中的​

​http/server​

​​中的​

​listen​

​參數下;

然後重新加載下​

​nginx​

​的配置檔案,讓其生效,使用如下指令:

./sbin/nginx -s reload      

最常見的解決方式就是按照上面的來,一般都能解決。

但是

但是

但是

但是

但是

我這裡不好使,為什麼呢?往下看。

實際解決方案

上面不是說了嘛,總的來說,慢的有兩個地方,一個是​

​sql​

​​查詢慢,還有一個就是前端加載慢(有部分影響)。前端就按照上面的解決沒問題,但是​

​sql​

​就不太行。

為啥呢,因為程式裡面實作某一功能的​

​sql​

​​,咋說的,寫的有點兒爛,怎麼個爛法呢,跨表查詢+嵌套查詢+​

​group by​

​​+​

​limit​

​​+​

​like​

​​+時間範圍查詢。就導緻了雖然這個​

​sql​

​中涉及的每個表的使用字段都配置了索引,但是并沒有命中,相當于無效了,而且,還不好弄。

當然了,最好的方式是讓程式修改裡面定義的​

​sql​

​檔案嘛,但是嘛。。。懂的都懂。

最後,通過在​

​mysql​

​​中添加緩存,這個緩存的作用是什麼呢,就是說,當你執行了一條​

​sql​

​,比如是:

select a,b,b from test_1 where time = '2022-07-27';      

你第一次執行這個指令的時候,​

​mysql​

​​的緩存會把這個​

​sql​

​和結果存放到緩存中。

隻要你涉及到這個查詢的資料沒有變化,那麼你後面再次查詢的時候,就不執行查詢了,而是直接把緩存中的這個結果傳回,這樣子就大大減少了查詢時間。

怎麼配置呢,還是需要修改​

​mysql​

​的配置檔案:

query_cache_size=2048M  # 緩存大小
query_cache_type=1  # 開啟緩存      

然後重新開機下資料庫;

systemctl restart mysqld.service      

當然了,也可以使用​

​global set​

​的方式臨時進行修改。

這樣子添加完之後,隻有第一次通路慢,後面就非常快了。

通過上面的操作之後,點選菜單的時間從2~3分鐘,優化到了14秒左右,客戶還是不是很滿意,因為他們需要操作的業務量還是挺大的。

那麼有沒有别的辦法呢,再次研究程式裡面定義的​

​sql​

​,看看是否能通過添加聯合索引,或者其他索引的方式來優化,你别說,還真的讓我發現了一個索引,添加完畢之後,時間再次砍半,由14秒,再次縮短到了7秒左右,這個時候客戶終于臨時接受了,并發函讓我們繼續整改。

我們也承諾會進行排期優化​

​sql​

​,并及時上線。

事情也就到此為止告一段落了。

總結

遇到這種資料庫慢的情況,無非就是先定位問題,然後再根據情況來優化,大機率是​

​sql​

​本身的問題,上線之初可能沒有進行稽核,隻是為了上線而上線了,測試資料也就幾百幾千條,完全沒有壓力測試吧。

這個處理方式,僅供參考,不可能所有的都可以按照這個方式來處理,你如果有更好的方式,歡迎通過公衆号“運維家”,來我的WX來和我交流。

至此,本文結束。 

更多内容請轉至VX公衆号 “運維家” ,擷取最新文章。

------ “運維家”  ------

------ “運維家”  ------

------ “運維家”  ------

臨武縣運維工程師教育訓練,溫州運維工程師,通達oa實施運維工程師,呼叫中心運維工程師面試