SQL脚本优化
1.創(chuàng)建索引
一.要盡量避免全表掃描,首先應(yīng)考慮在 where 及 order by 涉及的列上建立索引
? (1)在經(jīng)常需要進(jìn)行檢索的字段上創(chuàng)建索引,比如要按照表字段username進(jìn)行檢索,那么就應(yīng)該在姓名字段上創(chuàng)建索引,如果經(jīng)常要按照員工部門和員工崗位級(jí)別進(jìn)行檢索,那么就應(yīng)該在員工部門和員工崗位級(jí)別這兩個(gè)字段上創(chuàng)建索引。
? (2)創(chuàng)建索引給檢索帶來(lái)的性能提升往往是巨大的,因此在發(fā)現(xiàn)檢索速度過(guò)慢的時(shí)候應(yīng)該首先想到的就是創(chuàng)建索引。
? (3)一個(gè)表的索引數(shù)最好不要超過(guò)6個(gè),若太多則應(yīng)考慮一些不常使用到的列上建的索引是否有 必要。索引并不是越多越好,索引固然可以提高相應(yīng)的 select 的效率,但同時(shí)也降低了 insert 及 update 的效率,因?yàn)?insert 或 update 時(shí)有可能會(huì)重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。
2.避免在索引上使用計(jì)算
在where字句中,如果索引列是計(jì)算或者函數(shù)的一部分,DBMS的優(yōu)化器將不會(huì)使用索引而使用全表查詢,函數(shù)
屬于計(jì)算的一種,同時(shí)在in和exists中通常情況下使用EXISTS,因?yàn)閕n不走索引
效率低:
?select * from user where salary*22>11000(salary是索引列)
效率高:
?select * from user where salary>11000/22(salary是索引列)
?
如果where語(yǔ)句中有多個(gè)字段,那么可以考慮創(chuàng)建組合索引。
組合索引中字段的順序是非常重要的,越是唯一的字段越是要靠前。
另外,無(wú)論是組合索引還是單個(gè)列的索引,盡量不要選擇那些唯一性很低的字段。
比如說(shuō),在只有兩個(gè)值0和1的字段上建立索引沒(méi)有多大意義。
3.調(diào)整Where字句中的連接順序
ORACLE 采用自下而上的順序解析WHERE 子句,根據(jù)這個(gè)原理,表之間的連接必須寫在其他
WHERE 條件之前, 那些可以過(guò)濾掉最大數(shù)量記錄的條件必須寫在WHERE 子句的末尾.
4.用union all替換union
當(dāng)SQL語(yǔ)句需要union兩個(gè)查詢結(jié)果集合時(shí),即使檢索結(jié)果中不會(huì)有重復(fù)的記錄,如果使用union這兩個(gè)結(jié)果集
同樣會(huì)嘗試進(jìn)行合并,然后在輸出最終結(jié)果前進(jìn)行排序,因此如果可以判斷檢索結(jié)果中不會(huì)有重復(fù)的記錄時(shí)候,應(yīng)
該用union all,這樣效率就會(huì)因此得到提高。
5.考慮使用“臨時(shí)表”暫存中間結(jié)果
簡(jiǎn)化SQL語(yǔ)句的重要方法就是采用臨時(shí)表暫存中間結(jié)果,但是,臨時(shí)表的好處遠(yuǎn)遠(yuǎn)不止這些,將臨時(shí)結(jié)果暫存在臨時(shí)表,后面的查詢就在tempdb中了,這可以避免程序中多次掃描主表,也大大減少了程序執(zhí)行中“共享鎖”阻塞“更新鎖”,減少了阻塞,提高了并發(fā)性能。
但是也得避免頻繁創(chuàng)建和刪除臨時(shí)表,以減少系統(tǒng)表資源的消耗。
6.限制結(jié)果集
要盡量減少返回的結(jié)果行,包括行數(shù)和字段列數(shù),只提取必須要的字段
返回的結(jié)果越大,意味著相應(yīng)的SQL語(yǔ)句的logical reads 就越大,對(duì)服務(wù)器的性能影響就越甚。
一個(gè)很不好的設(shè)計(jì)就是返回表的所有數(shù)據(jù)
7.應(yīng)盡量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進(jìn)行全表掃描。
8.對(duì)查詢進(jìn)行優(yōu)化,應(yīng)盡量避免全表掃描,首先應(yīng)考慮在 where 及 order by 涉及的列上建立索引。
9.應(yīng)盡量避免在 where 子句中對(duì)字段進(jìn)行 null 值判斷,否則將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描,如:
???? select id from t where num is null
???? 可以在num上設(shè)置默認(rèn)值0,確保表中num列沒(méi)有null值,然后這樣查詢:
???? select id from t where num=0
??? ?
??? ?
10.應(yīng)盡量避免在 where 子句中使用 or 來(lái)連接條件,否則將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描,如:
???? select id from t where num=10 or num=20
???? 可以這樣查詢:
???? select id from t where num=10
???? union all
???? select id from t where num=20
11.下面的查詢也將導(dǎo)致全表掃描:(不能前置百分號(hào))
???? select id from t where name like ‘%abc%’
??? 若要提高效率,可以考慮全文檢索。
12.in 和 not in 也要慎用,否則會(huì)導(dǎo)致全表掃描,如:
???? select id from t where num in(1,2,3)
???? 對(duì)于連續(xù)的數(shù)值,能用 between 就不要用 in 了:
???? select id from t where num between 1 and 3
??? ?
13.應(yīng)盡量避免在 where 子句中對(duì)字段進(jìn)行表達(dá)式操作,這將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描。如:
???? select id from t where num/2=100
???? 應(yīng)改為:
???? select id from t where num=100*2
??? ?
14.應(yīng)盡量避免在where子句中對(duì)字段進(jìn)行函數(shù)操作,這將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描。如:
???? select id from t where substring(name,1,3)=’abc’–name以abc開(kāi)頭的id
???? select id from t where datediff(day,createdate,’2005-11-30′)=0–’2005-11-30′生成的id
???? 應(yīng)改為:
???? select id from t where name like ‘a(chǎn)bc%’
???? select id from t where createdate >= ’2005-11-30′ and createdate < ’2005-12-1′
??? ?
??? ?
15.不要在 where 子句中的“=”左邊進(jìn)行函數(shù)、算術(shù)運(yùn)算或其他表達(dá)式運(yùn)算,否則系統(tǒng)將可能無(wú)法正確使用索引。
16.很多時(shí)候用 exists 代替 in 是一個(gè)好的選擇:
???? select num from a where num in(select num from b)
???? 用下面的語(yǔ)句替換:
???? select num from a where exists(select 1 from b where num=a.num)
轉(zhuǎn)載于:https://www.cnblogs.com/hello-wei/p/11060131.html
總結(jié)
- 上一篇: sql语句列名为变量(Spring Bo
- 下一篇: 关于MongoDB数据库的总结