Delete..In.. 删除语句的优化再次探讨
有這樣一張成績表
CREATE TABLE stu_score
(
id int ,
stu_id int,
course_id int,
score int,
primary key(id)
)
可以這樣給它插入實驗值:
Insert into stu_score select rownum,dbms_random.value(0,10000),dbms_random.value(1,5),dbms_random.value(0,150) from dual connect by level<10001
然后需求來了,stu_id和course_id相同時,最高的成績保留,其余刪除。用日常話來說就是取每個學生單科的最佳成績。
第一種刪除方式:
delete from stu_score where (stu_id,course_id,score) not in (select stu_id,course_id,max(score) as score from stu_score group by stu_id,course_id);
處理結果:
SQL> delete from stu_score where (stu_id,course_id,score) not in (select stu_id,course_id,max(score) as score from stu_score group by stu_id,course_id); 已刪除1048行。 已用時間: 00: 00: 28.68
耗時約28秒,select stu_id,course_id,max(score) as score from stu_score group by stu_id,course_id的結果是8943條,這種刪除需要從一萬條里逐條取出去和8943條比對,比對次數為10000*8943次。雖說小表產生性能問題是小概率事件,但遲早會碰上。
這條刪除語句慢的原因部分在于 stu_id,course_id,score 都不是主鍵,沒有索引幫助,只能走全表查詢的路子。但是,從解釋計劃來看,cost的飆升段發生在Delete Statement,達到了八千多,和后面的查詢關系真心不大。我試了select * fromstu_score where (stu_id,course_id,score) not in (select stu_id,course_id,max(score) as score from stu_score group by stu_id,course_id) 這樣的語句,其中只是把delete替換成了select * ,執行起來就是秒出,并無delete時的阻滯。
有些書上提到過給甄別列stu_id,course_id,score 加上索引能加快刪除速度的說法,我嘗試過沒有效果。具體如下:
SQL> create index idx_stuscore_three on stu_score(stu_id,course_id,score); 索引已創建。 已用時間: 00: 00: 00.06 SQL> delete from stu_score where (stu_id,course_id,score) not in (select stu_id,course_id,max(score) as score from stu_score group by stu_id,course_id); 已刪除1011行。 已用時間: 00: 00: 29.47
第二種刪除方式:
delete from stu_score where id not in (select a.id from stu_score a,( select stu_id,course_id,max(score) as score from stu_score group by stu_id,course_id ) b
where a.stu_id=b.stu_id and a.course_id=b.course_id and a.score=b.score)
處理結果:
SQL> delete from stu_score where id not in (select a.id from stu_score a,( select stu_id,course_id,max(score) as score from stu_score group by stu_id,course_id ) b 2 where a.stu_id=b.stu_id and a.course_id=b.course_id and a.score=b.score); 已刪除1048行。 已用時間: 00: 00: 00.06
用時不到一秒,這種方式形成了一個id臨時結果集,一萬條里逐條拿id去看在不在這個結果集里,比對次數為10000次加一次結果集查詢。由于id是主鍵,有效利用了id上的索引,這自然比全表查詢要快。從解釋計劃上看,包括delete statement部分的cost只有區區三十幾。
第三種刪除方式:
delete from stu_score where not exists (
select null from stu_score a,
(select stu_id,course_id,max(score) as score from stu_score group by stu_id,course_id) b
where a.stu_id=b.stu_id and a.course_id=b.course_id and a.score=b.score and stu_score.id=a.id)
處理結果:
SQL> delete from stu_score where not exists ( 2 select null from stu_score a, 3 (select stu_id,course_id,max(score) as score from stu_score group by stu_id,course_id) b 4 where a.stu_id=b.stu_id and a.course_id=b.course_id and a.score=b.score and stu_score.id=a.id); 已刪除1048行。 已用時間: 00: 00: 00.12
用時不到一秒,這種方式取出每行id進行了一次存在性查詢,總體為一萬次存在性查詢。從解釋計劃上看,包括delete statement部分的cost也只有區區三十幾。
可以看出,雖然存在子查詢,但后兩種相當于一萬次函數調用,且函數參數只有一個,結果都是秒出;而第一種是10000*8943約九千萬次比對,比對參數還有三個,相當于九千萬次三個參數的函數調用,這自然落了下風。
由于SQL語句的度量不像程序般透徹,只能以運行時間去套函數調用的概念,目前水平也只能解釋到這個程度,大家見諒。
前作:https://www.cnblogs.com/heyang78/p/12263253.html
END
總結
以上是生活随笔為你收集整理的Delete..In.. 删除语句的优化再次探讨的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: K8S 之yaml文件参数介绍1
- 下一篇: 数学建模 匈牙利算法求解整数规划基本原理