子查詢更新操作的坑
首先建立如下測試表:
CREATE TABLE
course
(student_id
INT(11),course
VARCHAR(20));
INSERT INTO
course
VALUES (‘1‘, ‘測試1‘);INSERT INTO
course
VALUES (‘2‘, ‘測試2‘);INSERT INTO
course
VALUES (‘3‘, ‘測試3‘);
CREATE TABLE student
(id
INT(11),name
VARCHAR(20)
) ;
student
VALUES (‘1‘, ‘jiate‘);INSERT INTO
student
VALUES (‘2‘, ‘haoshen‘);INSERT INTO
student
VALUES (‘3‘, ‘leishen‘);INSERT INTO
student
VALUES (‘4‘, ‘tetui‘);
現在我們執行如下查詢操作:
SELECT FROM student WHERE id IN (SELECT id FROM course)
這個結果很明顯,多了一條。而在昨天,我們開發寫的是個update 操作,也是就:update student set name=‘特腿‘ where id in (select id from course) 本來更新1000條的數據,開發直接誤更新了40萬條。
我們 desc extended 看看優化器究竟幹了什麽?
DESC EXTENDED SELECT FROM student WHERE id IN (SELECT id FROM course)
SHOW WARNINGS
第一行1276 大意是說第二個查詢中的 id 列在第一個表中被解析到
第二行就是解析器解析後的sql,我們貼出來看看
SELECT yhtest
.student
.id
AS id
,yhtest
.student
.name
AS name
FROM
yhtest
.student
semi JOIN (
yhtest
.course
) WHERE (
yhtest
.student
.id
= yhtest
.student
.id
)
也就是說我們這個子查詢中的id 列被解析為了主表的id 列,這樣,where 條件是一個恒成立的條件,所以導致我們的查詢過結果是a表的全表結果,而這也是這樣的查詢不拋錯的原因。
子查詢中的字段,首先會在子查詢中查找,1)如果子查詢中沒該字段,則會去外層主表查找,如果能找到,也不會拋錯! 2)如果子查詢和主表中都沒有該字段,則會拋錯。
這其實是一個比較不理想的結果,如果我們無意中錯誤是update操作,那麽這個結果太糟糕。
這個我們提了兩個醒:
1)做數據庫操作之前,最好都備份
2)平時寫sql的時候,子查詢盡量都寫成表關聯的形式,表關聯形式,如果出現這種錯誤,會直接拋出錯誤。子查詢形式,雖然好懂,一目了然,但是性能一般不大好,再一個,如果掉進了以上這種誤更新坑中......
3)在不同版本的數據庫對於子查詢的優化操作也是不盡相同,性能差異在不同版本之間還是比較明顯的。
子查詢更新操作的坑