近日寫mysql儲存過程的時候伤极,有個SQL執(zhí)行不動:
UPDATE t_csi_comment
SET is_valid = 0
WHERE
comment_id IN (
SELECT
comment_id
FROM
(
SELECT
*
FROM
t_csi_comment
WHERE
DATE_FORMAT(comment_time, '%Y%m%d') BETWEEN 20170425
AND 20170528
ORDER BY
comment_id DESC
) a
GROUP BY
openid,
dlr_code
HAVING
count(1) > 2
);
很奇怪,按道理這條SQL的檢索量小于10W移斩,應該怎么慢也不會幾分鐘不動的地步上真。
單獨執(zhí)行子查詢:
SELECT
comment_id
FROM
(
SELECT
*
FROM
t_csi_comment
WHERE
DATE_FORMAT(comment_time, '%Y%m%d') BETWEEN 20170425
AND 20170528
ORDER BY
comment_id DESC
) a
GROUP BY
openid,
dlr_code
HAVING
count(1) > 2;
結(jié)果比想象中的快咬腋,1秒都不到,EXPLAIN后檢索量不到4W行睡互。我就郁悶了帝火。
EXPLANIN第一條update語句:
注意:select_type 里出現(xiàn)了 DEPENDENT SUBQUERY。
這意味著什么湃缎?——子查詢?nèi)Q于外面的查詢犀填,Mysql 先執(zhí)行外查詢,內(nèi)查詢根據(jù)這個查詢結(jié)果(如執(zhí)行計劃里所述嗓违,38196 rows)的每一條記錄組成新的查詢語句后執(zhí)行九巡。多重子查詢情況下,我已經(jīng)不想去解析它是如何轉(zhuǎn)換SQL了蹂季。? Mysql在這點上并不比人類聰明冕广。
解決辦法(子查詢轉(zhuǎn)換成聯(lián)表查詢):
UPDATE t_csi_comment a INNER JOIN
(
SELECT
comment_id
FROM
(
SELECT
*
FROM
t_csi_comment
WHERE
DATE_FORMAT(comment_time, '%Y%m%d') BETWEEN 20170425
AND 20170528
ORDER BY
comment_id DESC
) a
GROUP BY
openid,
dlr_code
HAVING
count(1) > 2
) b ON a.comment_id = b.comment_id;
SET a.is_valid = 0
毫秒級別完工疏日。
按理說,越復雜的程序邏輯關系要越明朗撒汉,出現(xiàn)復雜SQL的幾率要越低沟优。但是總會有一塊業(yè)務相對復雜多變,無法把控睬辐,或者就是整個系統(tǒng)的架構(gòu)不夠明朗挠阁,脫離不了復雜SQL。這是在UPDATE時發(fā)現(xiàn)的子查詢問題溯饵,在其它SQL語句中肯定也會有所體現(xiàn)侵俗,這是Mysql的查詢機制問題,子查詢會讓Mysql變笨丰刊。所以還是慎用子查詢隘谣,各種復雜SQL下盡量先測試吧。
著作權歸作者所有啄巧。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權寻歧,非商業(yè)轉(zhuǎn)載請注明出處≈绕停互聯(lián)網(wǎng)+時代熄求,時刻要保持學習,攜手千鋒PHP,Dream It Possible逗概。