近日寫(xiě)mysql儲(chǔ)存過(guò)程的時(shí)候擂达,有個(gè)SQL執(zhí)行不動(dòng):
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雷激,應(yīng)該怎么慢也不會(huì)幾分鐘不動(dòng)的地步。
單獨(dú)執(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語(yǔ)句:
注意:select_type 里出現(xiàn)了 DEPENDENT SUBQUERY平绩。
這意味著什么?——子查詢?nèi)Q于外面的查詢漠另,Mysql 先執(zhí)行外查詢捏雌,內(nèi)查詢根據(jù)這個(gè)查詢結(jié)果(如執(zhí)行計(jì)劃里所述,38196 rows)的每一條記錄組成新的查詢語(yǔ)句后執(zhí)行笆搓。多重子查詢情況下性湿,我已經(jīng)不想去解析它是如何轉(zhuǎn)換SQL了。? Mysql在這點(diǎn)上并不比人類(lèi)聰明满败。
解決辦法(子查詢轉(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
毫秒級(jí)別完工肤频。
按理說(shuō),越復(fù)雜的程序邏輯關(guān)系要越明朗算墨,出現(xiàn)復(fù)雜SQL的幾率要越低宵荒。但是總會(huì)有一塊業(yè)務(wù)相對(duì)復(fù)雜多變,無(wú)法把控净嘀,或者就是整個(gè)系統(tǒng)的架構(gòu)不夠明朗报咳,脫離不了復(fù)雜SQL。這是在UPDATE時(shí)發(fā)現(xiàn)的子查詢問(wèn)題挖藏,在其它SQL語(yǔ)句中肯定也會(huì)有所體現(xiàn)暑刃,這是Mysql的查詢機(jī)制問(wèn)題,子查詢會(huì)讓Mysql變笨膜眠。所以還是慎用子查詢岩臣,各種復(fù)雜SQL下盡量先測(cè)試吧溜嗜。
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán)架谎,非商業(yè)轉(zhuǎn)載請(qǐng)注明出處炸宵。互聯(lián)網(wǎng)+時(shí)代狐树,時(shí)刻要保持學(xué)習(xí)焙压,攜手千鋒PHP,Dream It Possible。