公司後台某模塊功能記錄日誌中有一個搜索功能,通過前段時間的產品使用時間區間進行搜索反饋有些卡頓,我發現這個搜索功能比較慢,要3秒左右才能出來,就決定對這裏做一下優化。

通過分析代碼和SQL發現最核心的問題在於一個區間查詢耗時太長,耗時2秒多,所以我決定看看這裏能不能優化,其中核心SQL為

SELECT  * FROM XXX_log WHERE (`ctime` BETWEEN '2017-09-11 09:34:13'  AND '2017-10-11 09:34:13')
and     id > 27851
AND column1 = 'xxx'
AND (column2 = 'null' OR LENGTH(column2) > 91)
ORDER BY  id DESC LIMIT 0, 30

這個查詢是一個簡單查詢,沒有聯表,就是單表的limit分頁查詢,外加一個時間區間和字段搜索,我通過SQL分析 explain 發現並未走索引,掃描區間也很大,由於該表擁有接近100萬的記錄,查詢的掃描區間接近50萬,我感覺這樣肯定是效率不高的。

然後查詢了一下數據,發現耗時確實在2.6秒左右,我起初的設想是,column2字段查詢肯定是沒法改了 ,畢竟那涉及到以前的業務,該字段這樣搜索查詢確實有違常理,但是既然之前的功能已經這樣設計了,現在去做調整,反而有可能有問題,那麼就只有在 id ctime column1下手了,id它寫死了,定了某條記錄開始進行查詢,我猜測可能之前的數據是測試數據或者是廢棄數據,那既然有個標尺,就不去動它,column1是固定的查詢值,這樣也沒法改,這樣的固定值在數據行中差異不明顯,加索引效果也不大,然後是ctime了,唯一能動文章的也只有它了。

然後我好好分析了一下這個模塊要實現的功能邏輯,就是查詢這段時間內符合要求的數據,這段時間,很明顯是一個月,能不能設定這個查詢區間只能查一個星期呢?

我改為一週內的時間區間查詢,肯定能降低查詢的查詢區間啊,然而令人遺憾的是,這個降低查詢區間間隔,並沒有多大效果,最後無奈,我給ctime添加了一個 normal index btree索引,加了索引後,我本以為一切都會好起來,誰知,explain後效果還是那樣!

mysql強制使用索引_搜索

可能用到的索引keys 主鍵 ctime ,然而呢 查詢區間還是接近45萬,效果並不明顯,查詢時間也還是2秒多,這可讓我犯難了,一時束手無策,思考許久,突然想到這感覺是索引沒有真正生效導致的,那麼能不能強制告訴mysql使用某個索引了,讓他主動是走某個索引,然後我查詢了資料 找到了force index(強制要走的那個索引) ,我馬上就試了一下

SELECT  * FROM XXX_log **force index(ctime)** WHERE (`ctime` BETWEEN '2017-09-11 09:34:13'  AND '2017-10-11 09:34:13')
and     id > 27851
AND column1 = 'xxx'
AND (column2 = 'null' OR LENGTH(column2) > 91)
ORDER BY  id DESC LIMIT 0, 30

果然 explain分析之後 使用了ctime索引

mysql強制使用索引_搜索_02

而且查詢區間降低到3萬多了,這個效果太明顯了,耗時降低到0.2秒左右,然後這個功能馬上從3秒才能打開降低到0.3秒就能打開了,這個優化效果令我非常滿意。

在和運維討論該表的數據時,運維提供方案説,看到該表數據量龐大 接近100萬,並且時間很多是2015年 2016年的,他提出可以轉移2015年 2016年的數據,我查看了一下,2015年和2016年的數據合計起來有70多萬了,佔據了絕大部分,如果轉移的話,確實有利於我們查詢啊,比對啊,更新啊之類的,因為這是一張日誌表,在某個期間具有時效性,畢竟大部分時候今年不會再看去年前年的查詢數據了,所以我覺得這種做法也有依據,也合理,恰逢同事請假休息,此事等他回來再做討論。