高級查詢在數據庫中用得是最頻繁的,也是應用最普遍的。html
Ø 基本經常使用查詢mysql
--select
select * from student;
--all 查詢全部
select all sex from student;
--distinct 過濾重複
select distinct sex from student;
--count 統計
select count(*) from student;
select count(sex) from student;
select count(distinct sex) from student;
--top 取前N條記錄
select top 3 * from student;
--alias column name 列重命名
select id as 編號, name '名稱', sex 性別 from student;
--alias table name 表重命名
select id, name, s.id, s.name from student s;
--column 列運算
select (age + id) col from student;
select s.name + '-' + c.name from classes c, student s where s.cid = c.id;
--where 條件
select * from student where id = 2;
select * from student where id > 7;
select * from student where id < 3;
select * from student where id <> 3;
select * from student where id >= 3;
select * from student where id <= 5;
select * from student where id !> 3;
select * from student where id !< 5;
--and 而且
select * from student where id > 2 and sex = 1;
--or 或者
select * from student where id = 2 or sex = 1;
--between ... and ... 至關於而且
select * from student where id between 2 and 5;
select * from student where id not between 2 and 5;
--like 模糊查詢
select * from student where name like '%a%';
select * from student where name like '%[a][o]%';
select * from student where name not like '%a%';
select * from student where name like 'ja%';
select * from student where name not like '%[j,n]%';
select * from student where name like '%[j,n,a]%';
select * from student where name like '%[^ja,as,on]%';
select * from student where name like '%[ja_on]%';
--in 子查詢
select * from student where id in (1, 2);
--not in 不在其中
select * from student where id not in (1, 2);
--is null 是空
select * from student where age is null;
--is not null 不爲空
select * from student where age is not null;
--order by 排序
select * from student order by name;
select * from student order by name desc;
select * from student order by name asc;
--group by 分組
按照年齡進行分組統計
select count(age), age from student group by age;
按照性別進行分組統計
select count(*), sex from student group by sex;
按照年齡和性別組合分組統計,並排序
select count(*), sex from student group by sex, age order by age;
按照性別分組,而且是id大於2的記錄最後按照性別排序
select count(*), sex from student where id > 2 group by sex order by sex;
查詢id大於2的數據,並完成運算後的結果進行分組和排序
select count(*), (sex * id) new from student where id > 2 group by sex * id order bysex * id;
--group by all 全部分組
按照年齡分組,是全部的年齡
select count(*), age from student group by all age;
--having 分組過濾條件
按照年齡分組,過濾年齡爲空的數據,而且統計分組的條數和現實年齡信息
select count(*), age from student group by age having age is not null;
按照年齡和cid組合分組,過濾條件是cid大於1的記錄
select count(*), cid, sex from student group by cid, sex having cid > 1;
按照年齡分組,過濾條件是分組後的記錄條數大於等於2
select count(*), age from student group by age having count(age) >= 2;
按照cid和性別組合分組,過濾條件是cid大於1,cid的最大值大於2
select count(*), cid, sex from student group by cid, sex having cid > 1 and max(cid) > 2;
Ø 嵌套子查詢程序員
子查詢是一個嵌套在select、insert、update或delete語句或其餘子查詢中的查詢。任何容許使用表達式的地方均可以使用子查詢。子查詢也稱爲內部查詢或內部選擇,而包含子查詢的語句也成爲外部查詢或外部選擇。web
# from (select … table)示例正則表達式
將一個table的查詢結果當作一個新表進行查詢
select * from (
select id, name from student where sex = 1
) t where t.id > 2;
上面括號中的語句,就是子查詢語句(內部查詢)。在外面的是外部查詢,其中外部查詢能夠包含如下語句:sql
一、 包含常規選擇列表組件的常規select查詢數據庫
二、 包含一個或多個表或視圖名稱的常規from語句性能優化
三、 可選的where子句併發
四、 可選的group by子句函數
五、 可選的having子句
# 示例
查詢班級信息,統計班級學生人生
select *, (select count(*) from student where cid = classes.id) as num
from classes order by num;
# in, not in子句查詢示例
查詢班級id大於小於的這些班級的學生信息
select * from student where cid in (
select id from classes where id > 2 and id < 4
);
查詢不是班的學生信息
select * from student where cid not in (
select id from classes where name = '2班'
)
in、not in 後面的子句返回的結果必須是一列,這一列的結果將會做爲查詢條件對應前面的條件。如cid對應子句的id;
# exists和not exists子句查詢示例
查詢存在班級id爲的學生信息
select * from student where exists (
select * from classes where id = student.cid and id = 3
);
查詢沒有分配班級的學生信息
select * from student where not exists (
select * from classes where id = student.cid
);
exists和not exists查詢須要內部查詢和外部查詢進行一個關聯的條件,若是沒有這個條件將是查詢到的全部信息。如:id等於student.id;
# some、any、all子句查詢示例
查詢班級的學生年齡大於班級的學生的年齡的信息
select * from student where cid = 5 and age > all (
select age from student where cid = 3
);
select * from student where cid = 5 and age > any (
select age from student where cid = 3
);
select * from student where cid = 5 and age > some (
select age from student where cid = 3
);
Ø 聚合查詢
一、 distinct去掉重複數據
select distinct sex from student;
select count(sex), count(distinct sex) from student;
二、 compute和compute by彙總查詢
對年齡大於的進行彙總
select age from student
where age > 20 order by age compute sum(age) by age;
對年齡大於的按照性別進行分組彙總年齡信息
select id, sex, age from student
where age > 20 order by sex, age compute sum(age) by sex;
按照年齡分組彙總
select age from student
where age > 20 order by age, id compute sum(age);
按照年齡分組,年齡彙總,id找最大值
select id, age from student
where age > 20 order by age compute sum(age), max(id);
compute進行彙總前面是查詢的結果,後面一條結果集就是彙總的信息。compute子句中能夠添加多個彙總表達式,能夠添加的信息以下:
a、 可選by關鍵字。它是每一列計算指定的行聚合
b、 行聚合函數名稱。包括sum、avg、min、max、count等
c、 要對其執行聚合函數的列
compute by適合作先分組後彙總的業務。compute by後面的列必定要是order by中出現的列。
三、 cube彙總
cube彙總和compute效果相似,但語法較簡潔,並且返回的是一個結果集。
select count(*), sex from student group by sex with cube;
select count(*), age, sum(age) from student where age is not null group by age withcube;
cube要結合group by語句完成分組彙總
Ø 排序函數
排序在不少地方須要用到,須要對查詢結果進行排序而且給出序號。好比:
一、 對某張表進行排序,序號須要遞增不重複的
二、 對學生的成績進行排序,得出名次,名次能夠並列,但名次的序號是連續遞增的
三、 在某些排序的狀況下,須要跳空序號,雖然是並列
基本語法
排序函數 over([分組語句] 排序子句[desc][asc])
排序子句 order by 列名, 列名
分組子句 partition by 分組列, 分組列
# row_number函數
根據排序子句給出遞增連續序號
按照名稱排序的順序遞增
select s.id, s.name, cid, c.name, row_number() over(order by c.name) as number
from student s, classes c where cid = c.id;
# rank函數函數
根據排序子句給出遞增的序號,可是存在並列而且跳空
順序遞增
select id, name, rank() over(order by cid) as rank from student;
跳過相同遞增
select s.id, s.name, cid, c.name, rank() over(order by c.name) as rank
from student s, classes c where cid = c.id;
# dense_rank函數
根據排序子句給出遞增的序號,可是存在並列不跳空
不跳過,直接遞增
select s.id, s.name, cid, c.name, dense_rank() over(order by c.name) as dense
from student s, classes c where cid = c.id;
# partition by分組子句
能夠完成對分組的數據進行增長排序,partition by能夠與以上三個函數聯合使用。
利用partition by按照班級名稱分組,學生id排序
select s.id, s.name, cid, c.name, row_number() over(partition by c.name order by s.id) as rank
from student s, classes c where cid = c.id;
select s.id, s.name, cid, c.name, rank() over(partition by c.name order by s.id) asrank
from student s, classes c where cid = c.id;
select s.id, s.name, cid, c.name, dense_rank() over(partition by c.name order by s.id) as rank
from student s, classes c where cid = c.id;
# ntile平均排序函數
將要排序的數據進行平分,而後按照等分排序。ntile中的參數表明分紅多少等分。
select s.id, s.name, cid, c.name,
ntile(5) over(order by c.name) as ntile
from student s, classes c where cid = c.id;
Ø 集合運算
操做兩組查詢結果,進行交集、並集、減集運算
一、 union和union all進行並集運算
--union 並集、不重複
select id, name from student where name like 'ja%'
union
select id, name from student where id = 4;
--並集、重複
select * from student where name like 'ja%'
union all
select * from student;
二、 intersect進行交集運算
--交集(相同部分)
select * from student where name like 'ja%'
intersect
select * from student;
三、 except進行減集運算
--減集(除相同部分)
select * from student where name like 'ja%'
except
select * from student where name like 'jas%';
Ø 公式表表達式
查詢表的時候,有時候中間表須要重複使用,這些子查詢被重複查詢調用,不但效率低,並且可讀性低,不利於理解。那麼公式表表達式能夠解決這個問題。
咱們能夠將公式表表達式(CET)視爲臨時結果集,在select、insert、update、delete或是create view語句的執行範圍內進行定義。
--表達式
with statNum(id, num) as
(
select cid, count(*)
from student
where id > 0
group by cid
)
select id, num from statNum order by id;
with statNum(id, num) as
(
select cid, count(*)
from student
where id > 0
group by cid
)
select max(id), avg(num) from statNum;
Ø 鏈接查詢
一、 簡化鏈接查詢
--簡化聯接查詢
select s.id, s.name, c.id, c.name from student s, classes c where s.cid = c.id;
二、 left join左鏈接
--左鏈接
select s.id, s.name, c.id, c.name from student s left join classes c on s.cid = c.id;
三、 right join右鏈接
--右鏈接
select s.id, s.name, c.id, c.name from student s right join classes c on s.cid = c.id;
四、 inner join內鏈接
--內鏈接
select s.id, s.name, c.id, c.name from student s inner join classes c on s.cid = c.id;
--inner能夠省略
select s.id, s.name, c.id, c.name from student s join classes c on s.cid = c.id;
一、 聚合函數
max最大值、min最小值、count統計、avg平均值、sum求和、var求方差
select
max(age) max_age,
min(age) min_age,
count(age) count_age,
avg(age) avg_age,
sum(age) sum_age,
var(age) var_age
from student;
二、 日期時間函數
select dateAdd(day, 3, getDate());--加天
select dateAdd(year, 3, getDate());--加年
select dateAdd(hour, 3, getDate());--加小時
--返回跨兩個指定日期的日期邊界數和時間邊界數
select dateDiff(day, '2011-06-20', getDate());
--相差秒數
select dateDiff(second, '2011-06-22 11:00:00', getDate());
--相差小時數
select dateDiff(hour, '2011-06-22 10:00:00', getDate());
select dateName(month, getDate());--當前月份
select dateName(minute, getDate());--當前分鐘
select dateName(weekday, getDate());--當前星期
select datePart(month, getDate());--當前月份
select datePart(weekday, getDate());--當前星期
select datePart(second, getDate());--當前秒數
select day(getDate());--返回當前日期天數
select day('2011-06-30');--返回當前日期天數
select month(getDate());--返回當前日期月份
select month('2011-11-10');
select year(getDate());--返回當前日期年份
select year('2010-11-10');
select getDate();--當前系統日期
select getUTCDate();--utc日期
作管理系統的,不管是bs結構的仍是cs結構的,都不可避免的涉及到數據庫表結構的設計,sql語句的編寫等。所以在開發系統的時候,表結構設計是否合理,sql語句是否標準,寫出的sql性能是否優化每每會成爲公司衡量程序員技術水平的標準。
咱們程序員不是dba,不須要時刻關注sql運行時間,千方百計優化表結構,存儲空間,優化表讀取速度等等,可是在開發系統時,時刻保持優良的寫sql語句的做風是頗有必要的,這關乎到我的在公司的聲譽,嘿嘿,你懂的。。。
新來的程序員老鳥,在一個開發團隊中,須要表現一下本身的水平,奠基在公司的地位,須要努力表現一把,最簡單的從寫的sql語句就很容易表現出來,曾經就有一次,一個老程序員,上面定位是要作團隊領導的,先歷練一下作個制單的模塊,列表sql中有一列這位老鳥直接寫了個select語句從別的表中取之,而不是用表之間關聯獲得,一下破壞本身程序員老鳥光輝形象。
作技術的仍是要注重本身的內涵,提高內功,哈哈。
閒話少說,總結一點程序員老鳥寫sql順手拈來的功夫吧:
1. 不論一個sql中涉及到多個表,每次都用兩個表(結果集)操做,獲得新的結果後,再和下一個表(結果集)操做。
2. 避免在select f1,(select f2 from tableB ).... from tableA 這樣獲得字段列。直接用tableA和tableB關聯獲得A.f1,B.f2就能夠了。
3.避免隱含的類型轉換
如
select id from employee where emp_id='8' (錯)
select id from employee where emp_id=8 (對)
emp_id是整數型,用'8'會默認啓動類型轉換,增長查詢的開銷。
4. 儘可能減小使用正則表達式,儘可能不使用通配符。
5. 使用關鍵字代替函數
如:
select id from employee where UPPER(dept) like 'TECH_DB' (錯)
select id from employee where SUBSTR(dept,1,4)='TECH' (錯)
select id from employee where dept like 'TECH%' (對)
6.不要在字段上用轉換函數,儘可能在常量上用
如:
select id from employee where to_char(create_date,'yyyy-mm-dd')='2012-10-31' (錯)
select id from employee where create_date=to_date('2012-10-31','yyyy-mm-dd') (對)
7.不使用聯接作查詢
如:select id from employee where first_name || last_name like 'Jo%' (錯)
8. 儘可能避免先後都用通配符
如:
select id from employee where dept like '%TECH%' (錯)
select id from employee where dept like 'TECH%' (對)
9. 判斷條件順序
如:
select id from employee where creat_date-30>to_date('2012-10-31','yyyy-mm-dd') (錯)
select id from employee where creat_date >to_date('2012-10-31','yyyy-mm-dd')+30 (對)
10. 儘可能使用exists而非in
固然這個也要根據記錄的狀況來定用exists仍是用in, 一般的狀況是用exists
select id from employee where salary in (select salary from emp_level where....) (錯)
select id from employee where salary exists(select 'X' from emp_level where ....) (對)
11. 使用not exists 而非not in
和上面的相似
12. 減小查詢表的記錄數範圍
13.正確使用索引
索引能夠提升速度,通常來講,選擇度越高,索引的效率越高。
14. 索引類型
惟一索引,對於查詢用到的字段,儘量使用惟一索引。
還有一些其餘類型,如位圖索引,在性別字段,只有男女的字段上用。
15. 在常常進行鏈接,可是沒有指定爲外鍵的列上創建索引
16. 在頻繁進行排序會分組的列上創建索引,如常常作group by 或 order by 操做的字段。
17. 在條件表達式中常常用到的不一樣值較多的列上創建檢索,在不一樣值少的列上不創建索引。如性別列上只有男,女兩個不一樣的值,就不必創建索引(或創建位圖索引)。若是創建索引不但不會提升查詢效率,反而會嚴重下降更新速度。
18. 在值比較少的字段作order by時,翻頁會出現記錄紊亂問題,要帶上id字段一塊兒作order by.
19. 不要使用空字符串進行查詢
如:
select id from employee where emp_name like '%%' (錯)
20. 儘可能對常常用做group by的關鍵字段作索引。
21. 正確使用表關聯
利用外鏈接替換效率十分低下的not in運算,大大提升運行速度。
如:
select a.id from employee a where a.emp_no not in (select emp_no from employee1 where job ='SALE') (錯)
22. 使用臨時表
在必要的狀況下,爲減小讀取次數,可使用通過索引的臨時表加快速度。
如:
select e.id from employee e ,dept d where e.dept_id=d.id and e.empno>1000 order by e.id (錯)
select id,empno from employee into temp_empl where empno>1000 order by id
select m.id from temp_emp1 m,dept d where m.empno=d.id (對)
對於大數據量sql語句性能優化更多的工做就交給dba去實踐,咱們程序員作好這些基本功就行了。
以上文章來着博客園web報表的博客。
1.對查詢進行優化,應儘可能避免全表掃描,首先應考慮在 where 及 order by 涉及的列上創建索引。
2.應儘可能避免在 where 子句中對字段進行 null 值判斷,不然將致使引擎放棄使用索引而進行全表掃描,如:
select id from t where num is null
能夠在num上設置默認值0,確保表中num列沒有null值,而後這樣查詢:
select id from t where num=0
3.應儘可能避免在 where 子句中使用!=或<>操做符,不然將引擎放棄使用索引而進行全表掃描。
4.應儘可能避免在 where 子句中使用 or 來鏈接條件,不然將致使引擎放棄使用索引而進行全表掃描,如:
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
5.in 和 not in 也要慎用,不然會致使全表掃描,如:
select id from t where num in(1,2,3)
對於連續的數值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
6.下面的查詢也將致使全表掃描:
select id from t where name like '%abc%'
若要提升效率,能夠考慮全文檢索。
7.若是在 where 子句中使用參數,也會致使全表掃描。由於SQL只有在運行時纔會解析局部變量,但優化程序不能將訪問計劃的選擇推遲到運行時;它必須在編譯時進行選擇。然而,若是在編譯時創建訪問計劃,變量的值仍是未知的,於是沒法做爲索引選擇的輸入項。以下面語句將進行全表掃描:
select id from t where num=@num <mailto:num=@num>
能夠改成強制查詢使用索引:
select id from t with(index(索引名)) where num=@num <mailto:num=@num>
8.應儘可能避免在 where 子句中對字段進行表達式操做,這將致使引擎放棄使用索引而進行全表掃描。如:
select id from t where num/2=100
應改成:
select id from t where num=100*2
9.應儘可能避免在where子句中對字段進行函數操做,這將致使引擎放棄使用索引而進行全表掃描。如:
select id from t where substring(name,1,3)='abc'--name以abc開頭的id
select id from t where datediff(day,createdate,'2005-11-30')=0--‘2005-11-30’生成的id
應改成:
select id from t where name like 'abc%'
select id from t where createdate>='2005-11-30' and createdate<'2005-12-1'
10.不要在 where 子句中的「=」左邊進行函數、算術運算或其餘表達式運算,不然系統將可能沒法正確使用索引。
11.在使用索引字段做爲條件時,若是該索引是複合索引,那麼必須使用到該索引中的第一個字段做爲條件時才能保證系統使用該索引,不然該索引將不會被使用,而且應儘量的讓字段順序與索引順序相一致。
12.不要寫一些沒有意義的查詢,如須要生成一個空表結構:
select col1,col2 into #t from t where 1=0
這類代碼不會返回任何結果集,可是會消耗系統資源的,應改爲這樣:
create table #t(...)
13.不少時候用 exists 代替 in 是一個好的選擇:
select num from a where num in(select num from b)
用下面的語句替換:
select num from a where exists(select 1 from b where num=a.num)
14.並非全部索引對查詢都有效,SQL是根據表中數據來進行查詢優化的,當索引列有大量數據重複時,SQL查詢可能不會去利用索引,如一表中有字段sex,male、female幾乎各一半,那麼即便在sex上建了索引也對查詢效率起不了做用。
15.索引並非越多越好,索引當然能夠提升相應的 select 的效率,但同時也下降了 insert 及 update 的效率,由於 insert 或 update 時有可能會重建索引,因此怎樣建索引須要慎重考慮,視具體狀況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有必要。
16.應儘量的避免更新 clustered 索引數據列,由於 clustered 索引數據列的順序就是表記錄的物理存儲順序,一旦該列值改變將致使整個表記錄的順序的調整,會耗費至關大的資源。若應用系統須要頻繁更新 clustered 索引數據列,那麼須要考慮是否應將該索引建爲 clustered 索引。
17.儘可能使用數字型字段,若只含數值信息的字段儘可能不要設計爲字符型,這會下降查詢和鏈接的性能,並會增長存儲開銷。這是由於引擎在處理查詢和鏈接時會逐個比較字符串中每個字符,而對於數字型而言只須要比較一次就夠了。
18.儘量的使用 varchar/nvarchar 代替 char/nchar ,由於首先變長字段存儲空間小,能夠節省存儲空間,其次對於查詢來講,在一個相對較小的字段內搜索效率顯然要高些。
19.任何地方都不要使用 select * from t ,用具體的字段列表代替「*」,不要返回用不到的任何字段。
20.儘可能使用表變量來代替臨時表。若是表變量包含大量數據,請注意索引很是有限(只有主鍵索引)。
21.避免頻繁建立和刪除臨時表,以減小系統表資源的消耗。
22.臨時表並非不可以使用,適當地使用它們可使某些例程更有效,例如,當須要重複引用大型表或經常使用表中的某個數據集時。可是,對於一次性事件,最好使用導出表。
23.在新建臨時表時,若是一次性插入數據量很大,那麼可使用 select into 代替 create table,避免形成大量 log ,以提升速度;若是數據量不大,爲了緩和系統表的資源,應先create table,而後insert。
24.若是使用到了臨時表,在存儲過程的最後務必將全部的臨時表顯式刪除,先 truncate table ,而後 drop table ,這樣能夠避免系統表的較長時間鎖定。
25.儘可能避免使用遊標,由於遊標的效率較差,若是遊標操做的數據超過1萬行,那麼就應該考慮改寫。
26.使用基於遊標的方法或臨時表方法以前,應先尋找基於集的解決方案來解決問題,基於集的方法一般更有效。
27.與臨時表同樣,遊標並非不可以使用。對小型數據集使用 FAST_FORWARD 遊標一般要優於其餘逐行處理方法,尤爲是在必須引用幾個表才能得到所需的數據時。在結果集中包括「合計」的例程一般要比使用遊標執行的速度快。若是開發時間容許,基於遊標的方法和基於集的方法均可以嘗試一下,看哪種方法的效果更好。
28.在全部的存儲過程和觸發器的開始處設置 SET NOCOUNT ON ,在結束時設置 SET NOCOUNT OFF 。無需在執行存儲過程和觸發器的每一個語句後向客戶端發送 DONE_IN_PROC 消息。
29.儘可能避免大事務操做,提升系統併發能力。
30.儘可能避免向客戶端返回大數據量,若數據量過大,應該考慮相應需求是否合理。
兩篇文章來源: