一:理解sql執行順序javascript
在sql中,第一個被執行的是from語句,每個步驟都會產生一個虛擬表,該表供下一個步驟查詢時調用,好比語句:select top 10 column1,colum2,max(column3) from user where id>1 group by column1,colum2 having count(column1)>1 order by colum2.html
sqlserver 2005 各個環節簡單介紹:java
(8)SELECT (9)DISTINCT (11)<Top Num> <select list>mysql
(1)FROM [left_table]sql
(3)<join_type> JOIN <right_table>數據庫
(2)ON <join_condition>服務器
(4)WHERE <where_condition>併發
(5)GROUP BY <group_by_list>app
(6)WITH <CUBE | RollUP>ide
(7)HAVING <having_condition>
(10)ORDER BY <order_by_list>
a)各個步驟簡介:
b)標準sql執行順序是:
1:form 組裝來自不一樣表的數據,如 form user或者,form user as u join goodsOrder as r on u.id= r.userid
2:where 過濾符合查詢條件的數據,如:id>1000
3:group by 將查詢數據進行分組
4:使用sum等聚合函數進行計算。
5:使用having 進行篩選分組。
6:執行select語種
7:執行排序語句
如:select count(gid),gname from shopping_goods where gcid=1 group by gname having count(gid)>1 order by count(gid) desc
1:首頁查詢shopping_goods 表,獲得表中的數據
2:執行where,過濾出gcid=1的商品。
3:對gname進行分組。
4:使用聚合函數count(),計算出商品類型爲1,不一樣商品名稱的數量.
5:使用having,過濾出類型爲1,商品統計數量大於1的商品
6:執行select語句
7:執行order by ,按照商品數量降序排列。
二:百萬數據量優化
這裏只介紹查詢和修改的方法,若是是系統優化,須要從表結構,索引,表分區等方面處理。
1:合理使用索引,在一個大數據量的表中,並非索引越多越好,索引越多,寫操做越慢,建議在如下字段上建立索引。
●在常常進行鏈接,可是沒有指定爲外鍵的列上創建索引,而不常常鏈接的字段則由優化器自動生成索引。
●在頻繁進行排序或分組(即進行group by或order by操做)的列上創建索引。
●在條件表達式中常常用到的不一樣值較多的列上創建檢索,在不一樣值少的列上不要創建索引。好比在僱員表的「性別」列上只有「男」與「女」兩個不一樣值,所以就無必要創建索引。若是創建索引不但不會提升查詢效率,反而會嚴重下降更新速度。
●若是待排序的列有多個,能夠在這些列上創建複合索引(compound index)。
●使用系統工具。如Informix數據庫有一個tbcheck工具,能夠在可疑的索引上進行檢查。在一些數據庫服務器上,索引可能失效或者由於頻繁操做而使得讀取效率下降,若是一個使用索引的查詢不明不白地慢下來,能夠試着用tbcheck工具檢查索引的完整性,必要時進行修復。另外,當數據庫表更新大量數據後,刪除並重建索引能夠提升查詢速度。
2:儘可能少用(或者不用)sqlserver 自帶的函數
a):如dateadd(month,-1,getdate()),請使用time>'2017-09-19 23:42:44.770 '代替dateadd.
b):如datediff(day,'2017-10-20','2017-10-25'),select datepart(day,getdate());,如需計算兩個日期以前的差值,或者獲得日期中的整數部分,建議查詢完畢後用java程序來計算,不要什麼都讓數據庫來作.
c:) 如:substring(name,1,3) = ’abc’,建議修改成 name like 'abc%'
3:儘可能不要在 where 子句中對字段進行 null 值判斷,不然將致使引擎放棄使用索引而進行全表掃描,強烈建議where涉及的列,不要留空,建立表時賦予初始值
錯誤
select id from table where name is not null
正確
create table table(name varchar(20) default '')
4:應儘可能避免在 where 子句中使用 != 或 <> 操做符,不然將引擎放棄使用索引而進行全表掃描。
錯誤
select id from table where id <> 100
5:應儘可能避免在 where 子句中使用 or 來鏈接條件,若是一個字段有索引,一個字段沒有索引,將致使引擎放棄使用索引而進行全表掃描,建議使用unall 來代替or
select id from table where num=1 or Name = 'zhangsan'
建議修改成
select id from table where num=1
unionall
select id from table where name = 'zhangsan'
6:建議使用exists 來代替in,能用between 就不要使用in 如:age in (20,21,22)建議修改成:age between 20 and 22
select id from t where role in (select rid from role where rName = '經理')
建議修改成
select id from t as a where exists (select rid from role as b where a.role = b.rid and rName = '經理')
7:like 的用法
除了 title like '重慶%' ,其它使用方法(如:title like '%王%' title like '%天')也將致使全表掃描
8:where 中儘可能不要出現表達式計算
如:
select id from t where num/2 = 100
應改成:
select id from t where num = 100*2
9:Update 語句,若是隻更改一、2個字段,不要Update所有字段,不然頻繁調用會引發明顯的性能消耗,同時帶來大量日誌。強烈建議修改時使用動態sql語句,相似hibernate中dynamic-update=true,不過hibernate須要將修改對像經過id查詢出來,纔會動態修改,若是是普通sql,直接組裝就能夠。
10:對於多張大數據量(這裏幾百條就算大了)的表JOIN,要先分頁再JOIN,不然邏輯讀會很高,性能不好.
11:不要寫一些沒有意義的查詢,如須要生成一個空表結構:
select col1,col2 into #t from t where 1=0
12:儘可能使用數字型字段,若只含數值信息的字段儘可能不要設計爲字符型,這會下降查詢和鏈接的性能,並會增長存儲開銷。這是由於引擎在處理查詢和連 接時會逐個比較字符串中每個字符,而對於數字型而言只須要比較一次就夠了。
13:儘量的使用 varchar/nvarchar 代替 char/nchar ,由於首先變長字段存儲空間小,能夠節省存儲空間,其次對於查詢來講,在一個相對較小的字段內搜索效率顯然要高些。
14:不建議使用 select * from t ,用具體的字段列表代替「*」,不要返回用不到的任何字段。
15:儘可能避免使用遊標,由於遊標的效率較差,若是遊標操做的數據超過1萬行,那麼就應該考慮改寫。
16:在全部的存儲過程和觸發器的開始處設置 SET NOCOUNT ON ,在結束時設置 SET NOCOUNT OFF 。無需在執行存儲過程和觸發器的每一個語句後向客戶端發送 DONE_IN_PROC 消息。
17:儘可能避免大事務操做,提升系統併發能力。而且不要事務嵌套,不要在事務中去調用其它系統的接口,不要在事務中耗時操做,否則死鎖並伴你左右。
18:儘可能避免向客戶端返回大數據量,若數據量過大,應該考慮相應需求是否合理。(筆者曾經處理過,從3000萬手機號碼庫中,模糊查詢出上萬個手機號碼,這種需求是客戶硬性要求,就要經過executorservice了,不要直接寫sql查)
19:若是數據庫是mysql,必定要利用數據庫引擎,不一樣業務要使用不一樣的數據庫引擎。好比經常使用的innodb和myisam,innodb支持事務,支持外鍵,鎖是表級鎖,缺點是查詢速度慢,Myisam 的執行速度更快,性能更好,但不支持外鍵,不支持事務,鎖是行鎖級。好比日誌表,數據量大,強烈建議使用myisam引擎.