一 問題描述
生產有一個這樣的慢sql:
SELECT DISTINCT
m1.meetingid AS meetingid,
m1.starttime AS START,
m1.endtime AS END,
m1.title AS title,
j.userid AS uid,
j.type AS TYPE,
m1.cuserid AS cuserid
FROM
MEETINGINFO m1
INNER JOIN JOININFO j
ON (m1.meetingid = j.meetingid)
AND (
m1.cuserid IN (192379)
OR j.userid IN (192379)
)
AND m1.dostatus IN (2, 4)
ORDER BY m1.starttime DESC
LIMIT 0, 10
查詢需要2.3秒。
MEETINGINFO有三十萬條數據,JOININFO有將近98萬條數據。
執行計劃如下:
二 優化思路
看到查詢條件裏有m1.cuserid IN (192379),卻選擇了starttime這個索引來掃描m1,遂查詢下該列上是否有索引:
SHOW INDEXES FROM MEETINGINFO #看到沒有相關索引
再看下該列是否適合創建索引:
重複率不算高,還可以。
嘗試在該列上創建索引:
CREATE INDEX ind_cuserid ON MEETINGINFO(cuserid);
發現執行計劃依然沒選擇走該索引,原因有二:
① cuserid是varchar類型的,而sql裏192379是數值類型,發生數據類型轉換,會導致索引失效
② OR j.userid IN (192379)裏的OR會導致無法走索引,需要用UNION ALL來代替OR。
三 解決辦法
改寫sql:
SELECT DISTINCT aa.meetingid,aa.start,aa.end,aa.title,aa.uid,aa.type,aa.cuserid
FROM
(SELECT
m1.meetingid AS meetingid,
m1.starttime AS START,
m1.endtime AS END,
m1.title AS title,
j.userid AS uid,
j.type AS TYPE,
m1.cuserid AS cuserid
FROM
MEETINGINFO m1
INNER JOIN JOININFO j
ON (m1.meetingid = j.meetingid)
AND (m1.cuserid IN ('192379'))
AND m1.dostatus IN (2, 4)
UNION ALL
(SELECT
m1.meetingid AS meetingid,
m1.starttime AS START,
m1.endtime AS
END,
m1.title AS title,
j.userid AS uid,
j.type AS TYPE,
m1.cuserid AS cuserid
FROM
MEETINGINFO m1
INNER JOIN JOININFO j
ON (m1.meetingid = j.meetingid)
AND j.userid IN ('192379')
AND m1.dostatus IN (2, 4)
)
) aa
ORDER BY aa.start DESC LIMIT 0,10
查詢時間從2秒多降到了0.02秒。
執行計劃如下: