Sql養成一個好習慣是一筆財富

????????? 我們做軟件開發的,大部分人都離不開跟數據庫打交道,特別是erp開發的,跟數據庫打交道更是頻繁,存儲過程動不動就是上千行,如果數據量大,人員流動大,那么我么還能保證下一段時間系統還能流暢的運行嗎?我么還能保證下一個人能看懂我么的存儲過程嗎?那么我結合公司平時的培訓和平時個人工作經驗和大家分享一下,希望對大家有幫助。

???? 要知道sql語句,我想我們有必要知道sqlserver查詢分析器怎么執行我么sql語句的,我么很多人會看執行計劃,或者用profile來監視和調優查詢語句或者存儲過程慢的原因,但是如果我們知道查詢分析器的執行邏輯順序,下手的時候就胸有成竹,那么下手是不是有把握點呢?

?? 一:查詢的邏輯執行順序

(1) FROM < left_table>?

(3) < join_type>? JOIN < right_table>?? (2) ON < join_condition>?

(4) WHERE < where_condition>?

(5) GROUP BY < group_by_list>?

(6) WITH {cube | rollup}

(7) HAVING < having_condition>?

(8) SELECT? (9) DISTINCT (11) < top_specification>? < select_list>?

(10) ORDER BY < order_by_list>?

標準的SQL 的解析順序為:

(1).FROM 子句 組裝來自不同數據源的數據

(2).WHERE 子句 基于指定的條件對記錄進行篩選

(3).GROUP BY 子句 將數據劃分為多個分組

(4).使用聚合函數進行計算

(5).使用HAVING子句篩選分組

(6).計算所有的表達式

(7).使用ORDER BY對結果集進行排序

二 執行順序:

???

1.FROM:對FROM子句中前兩個表執行笛卡爾積生成虛擬表vt1

2.ON:對vt1表應用ON篩選器只有滿足< join_condition> 為真的行才被插入vt2

3.OUTER(join):如果指定了 OUTER JOIN保留表(preserved table)中未找到的行將行作為外部行添加到vt2 生成t3如果from包含兩個以上表則對上一個聯結生成的結果表和下一個表重復執行步驟和步驟直接結束

4.WHERE:對vt3應用 WHERE 篩選器只有使< where_condition> 為true的行才被插入vt4

5.GROUP BY:按GROUP BY子句中的列列表對vt4中的行分組生成vt5

6.CUBE|ROLLUP:把超組(supergroups)插入vt6 生成vt6

7.HAVING:對vt6應用HAVING篩選器只有使< having_condition> 為true的組才插入vt7

8.SELECT:處理select列表產生vt8

9.DISTINCT:將重復的行從vt8中去除產生vt9

10.ORDER BY:將vt9的行按order by子句中的列列表排序生成一個游標vc10

11.TOP:從vc10的開始處選擇指定數量或比例的行生成vt11 并返回調用者

?????

???????? 看到這里,那么用過linqtosql的語法有點相似啊?如果我們我們了解了sqlserver執行順序,那么我們就接下來進一步養成日常sql好習慣,也就是在實現功能同時有考慮性能的思想,數據庫是能進行集合運算的工具,我們應該盡量的利用這個工具,所謂集合運算實際就是批量運算,就是盡量減少在客戶端進行大數據量的循環操作,而用SQL語句或者存儲過程代替。

三、只返回需要的數據

? 返回數據到客戶端至少需要數據庫提取數據、網絡傳輸數據、客戶端接收數據以及客戶端處理數據等環節,如果返回不需要的數據,就會增加服務器、網絡和客戶端的無效勞動,其害處是顯而易見的,避免這類事件需要注意:

? A、橫向來看,

? (1)不要寫SELECT *的語句,而是選擇你需要的字段。

? (2)當在SQL語句中連接多個表時, 請使用表的別名并把別名前綴于每個Column上.這樣一來,就可以減少解析的時間并減少那些由Column歧義引起的語法錯誤。

view sourceprint?
01如有表table1(ID,col1)和table2 (ID,col2)
02?
03 Select A.ID, A.col1, B.col2
04?
05 -- Select A.ID, col1, col2 –不要這么寫,不利于將來程序擴展
06?
07 from table1 A inner join table2 B on A.ID=B.ID Where
08?
09 B、縱向來看,
10?
11 (1)合理寫WHERE子句,不要寫沒有WHERE的SQL語句。
12?
13 (2) SELECT TOP N * --沒有WHERE條件的用此替代

四 :盡量少做重復的工作

A、控制同一語句的多次執行,特別是一些基礎數據的多次執行是很多程序員很少注意的。

B、減少多次的數據轉換,也許需要數據轉換是設計的問題,但是減少次數是程序員可以做到的。

C、杜絕不必要的子查詢和連接表,子查詢在執行計劃一般解釋成外連接,多余的連接表帶來額外的開銷。

D、合并對同一表同一條件的多次UPDATE,比如

view sourceprint?
UPDATE EMPLOYEE SET FNAME='HAIWER'
WHERE EMP_ID=' VPA30890F' UPDATE EMPLOYEE SET LNAME='YANG'
WHERE EMP_ID=' VPA30890F'
這兩個語句應該合并成以下一個語句
UPDATE EMPLOYEE SET FNAME='HAIWER',LNAME='YANG'? WHERE EMP_ID=' VPA30890F'

E、UPDATE操作不要拆成DELETE操作+INSERT操作的形式,雖然功能相同,但是性能差別是很大的。

五、注意臨時表和表變量的用法

在復雜系統中,臨時表和表變量很難避免,關于臨時表和表變量的用法,需要注意:

A、如果語句很復雜,連接太多,可以考慮用臨時表和表變量分步完成。

B、如果需要多次用到一個大表的同一部分數據,考慮用臨時表和表變量暫存這部分數據。

C、如果需要綜合多個表的數據,形成一個結果,可以考慮用臨時表和表變量分步匯總這多個表的數據。

D、其他情況下,應該控制臨時表和表變量的使用。

E、關于臨時表和表變量的選擇,很多說法是表變量在內存,速度快,應該首選表變量,但是在實際使用中發現,

(1)主要考慮需要放在臨時表的數據量,在數據量較多的情況下,臨時表的速度反而更快。

(2)執行時間段與預計執行時間(多長)

F、關于臨時表產生使用SELECT INTO和CREATE TABLE + INSERT INTO的選擇,一般情況下,

SELECT INTO會比CREATE TABLE + INSERT INTO的方法快很多,

但是SELECT INTO會鎖定TEMPDB的系統表SYSOBJECTS、SYSINDEXES、SYSCOLUMNS,在多用戶并發環境下,容易阻塞其他進程,

所以我的建議是,在并發系統中,盡量使用CREATE TABLE + INSERT INTO,而大數據量的單個語句使用中,使用SELECT INTO。

六、子查詢的用法(1)

? 子查詢是一個 SELECT 查詢,它嵌套在 SELECT、INSERT、UPDATE、DELETE 語句或其它子查詢中。

任何允許使用表達式的地方都可以使用子查詢,子查詢可以使我們的編程靈活多樣,可以用來實現一些特殊的功能。但是在性能上,

往往一個不合適的子查詢用法會形成一個性能瓶頸。如果子查詢的條件中使用了其外層的表的字段,這種子查詢就叫作相關子查詢。

相關子查詢可以用IN、NOT IN、EXISTS、NOT EXISTS引入。 關于相關子查詢,應該注意:

(1)

A、NOT IN、NOT EXISTS的相關子查詢可以改用LEFT JOIN代替寫法。比如: SELECT PUB_NAME FROM PUBLISHERS WHERE PUB_ID NOT IN (SELECT PUB_ID FROM TITLES WHERE TYPE = 'BUSINESS') 可以改寫成: SELECT A.PUB_NAME FROM PUBLISHERS A LEFT JOIN TITLES B ON B.TYPE = 'BUSINESS' AND A.PUB_ID=B. PUB_ID WHERE B.PUB_ID IS NULL
(2)
view sourceprint?
01SELECT TITLE FROM TITLES
02WHERE NOT EXISTS
03 (SELECT TITLE_ID FROM SALES
04WHERE TITLE_ID = TITLES.TITLE_ID)
05可以改寫成:
06SELECT TITLE
07FROM TITLES LEFT JOIN SALES
08ON SALES.TITLE_ID = TITLES.TITLE_ID
09WHERE SALES.TITLE_ID IS NULL
10B、 如果保證子查詢沒有重復 ,IN、EXISTS的相關子查詢可以用INNER JOIN 代替。比如:
11SELECT PUB_NAME
12FROM PUBLISHERS
13WHERE PUB_ID IN
14 (SELECT PUB_ID
15 FROM TITLES
16 WHERE TYPE = 'BUSINESS')
17可以改寫成:
18SELECT A.PUB_NAME --SELECT DISTINCT A.PUB_NAME
19FROM PUBLISHERS A INNER JOIN TITLES B
20ON??????? B.TYPE = 'BUSINESS' AND
21A.PUB_ID=B. PUB_ID
(3)
view sourceprint?
1C、 IN的相關子查詢用EXISTS代替,比如
2SELECT PUB_NAME FROM PUBLISHERS
3WHERE PUB_ID IN
4(SELECT PUB_ID FROM TITLES WHERE TYPE = 'BUSINESS')
5可以用下面語句代替:
6SELECT PUB_NAME FROM PUBLISHERS WHERE EXISTS
7(SELECT 1 FROM TITLES WHERE TYPE = 'BUSINESS' AND
8PUB_ID= PUBLISHERS.PUB_ID)
9D、不要用COUNT(*)的子查詢判斷是否存在記錄,最好用LEFT JOIN或者EXISTS,比如有人寫這樣的語句:
view sourceprint?
01SELECT JOB_DESC FROM JOBS
02WHERE (SELECT COUNT(*) FROM EMPLOYEE WHERE JOB_ID=JOBS.JOB_ID)=0
03應該改成:
04SELECT JOBS.JOB_DESC FROM JOBS LEFT JOIN EMPLOYEE?
05ON EMPLOYEE.JOB_ID=JOBS.JOB_ID
06WHERE EMPLOYEE.EMP_ID IS NULL
07?
08SELECT JOB_DESC FROM JOBS
09WHERE (SELECT COUNT(*) FROM EMPLOYEE WHERE JOB_ID=JOBS.JOB_ID)<>0
10應該改成:
11SELECT JOB_DESC FROM JOBS
12WHERE EXISTS (SELECT 1 FROM EMPLOYEE WHERE JOB_ID=JOBS.JOB_ID)
 七:盡量使用索引 

建立索引后,并不是每個查詢都會使用索引,在使用索引的情況下,索引的使用效率也會有很大的差別。只要我們在查詢語句中沒有強制指定索引,

索引的選擇和使用方法是SQLSERVER的優化器自動作的選擇,而它選擇的根據是查詢語句的條件以及相關表的統計信息,這就要求我們在寫SQL

語句的時候盡量使得優化器可以使用索引。為了使得優化器能高效使用索引,寫語句的時候應該注意:

(1
view sourceprint?
1A、不要對索引字段進行運算,而要想辦法做變換,比如
2??? SELECT ID FROM T WHERE NUM/2=100
3??? 應改為:
4??? SELECT ID FROM T WHERE NUM=100*2
5?
6??? SELECT ID FROM T WHERE NUM/2=NUM1
7??? 如果NUM有索引應改為:
8??? SELECT ID FROM T WHERE NUM=NUM1*2
9??? 如果NUM1有索引則不應該改。

(2)

view sourceprint?
01發現過這樣的語句:
02??? SELECT 年,月,金額 FROM 結余表? WHERE 100*年+月=2010*100+10
03??? 應該改為:
04??? SELECT 年,月,金額 FROM 結余表 WHERE 年=2010 AND月=10
05?
06B、 不要對索引字段進行格式轉換
07日期字段的例子:
08WHERE CONVERT(VARCHAR(10), 日期字段,120)='2010-07-15'
09應該改為
10WHERE日期字段〉='2010-07-15'?? AND?? 日期字段<'2010-07-16'
11?
12ISNULL轉換的例子:
13WHERE ISNULL(字段,'')<>''應改為:WHERE字段<>''
14WHERE ISNULL(字段,'')=''不應修改
15WHERE ISNULL(字段,'F') ='T'應改為: WHERE字段='T'
16WHERE ISNULL(字段,'F')<>'T'不應修改

(3)

view sourceprint?
01C、 不要對索引字段使用函數
02WHERE LEFT(NAME, 3)='ABC' 或者WHERE SUBSTRING(NAME,1, 3)='ABC'
03應改為: WHERE NAME LIKE 'ABC%'
04日期查詢的例子:
05WHERE DATEDIFF(DAY, 日期,'2010-06-30')=0
06應改為:WHERE 日期>='2010-06-30' AND 日期 <'2010-07-01'
07WHERE DATEDIFF(DAY, 日期,'2010-06-30')>0
08應改為:WHERE 日期 <'2010-06-30'
09WHERE DATEDIFF(DAY, 日期,'2010-06-30')>=0
10應改為:WHERE 日期 <'2010-07-01'
11WHERE DATEDIFF(DAY, 日期,'2010-06-30')<0
12應改為:WHERE 日期>='2010-07-01'
13WHERE DATEDIFF(DAY, 日期,'2010-06-30')<=0
14應改為:WHERE 日期>='2010-06-30'

D、不要對索引字段進行多字段連接

? 比如:

? WHERE FAME+ '. '+LNAME='HAIWEI.YANG'

? 應改為:

? WHERE FNAME='HAIWEI' AND LNAME='YANG'

?

八:多表連接的連接條件對索引的選擇有著重要的意義,所以我們在寫連接條件條件的時候需要特別注意。

? A、多表連接的時候,連接條件必須寫全,寧可重復,不要缺漏。

? B、連接條件盡量使用聚集索引

? C、注意ON、WHERE和HAVING部分條件的區別

? ON是最先執行, WHERE次之,HAVING最后,因為ON是先把不符合條件的記錄過濾后才進行統計,它就可以減少中間運算要處理的數據,按理說應該速度是最快的,WHERE也應該比 HAVING快點的,因為它過濾數據后才進行SUM,在兩個表聯接時才用ON的,所以在一個表的時候,就剩下WHERE跟HAVING比較了

view sourceprint?
1考慮聯接優先順序:
2(1)INNER JOIN
3(2)LEFT JOIN (注:RIGHT JOIN LEFT JOIN 替代)
4(3)CROSS JOIN

其它注意和了解的地方有:

A、在IN后面值的列表中,將出現最頻繁的值放在最前面,出現得最少的放在最后面,減少判斷的次數

B、注意UNION和UNION ALL的區別。--允許重復數據用UNION ALL好??

C、注意使用DISTINCT,在沒有必要時不要用

D、TRUNCATE TABLE 與 DELETE 區別

E、減少訪問數據庫的次數

還有就是我們寫存儲過程,如果比較長的話,最后用標記符標開,因為這樣可讀性很好,即使語句寫的不怎么樣但是語句工整,C# 有region

sql我比較喜歡用的就是

view sourceprint?
--startof? 查詢在職人數
???? sql語句
? --end of

?????

????????? 正式機器上我們一般不能隨便調試程序,但是很多時候程序在我們本機上沒問題,但是進正式系統就有問題,但是我們又不能隨便在正式機器上操作,那么怎么辦呢?我們可以用回滾來調試我們的存儲過程或者是sql語句,從而排錯。

view sourceprint?
BEGIN TRAN
UPDATE a SET 字段=''
ROLLBACK

??????

????? 作業存儲過程我一般會加上下面這段,這樣檢查錯誤可以放在存儲過程,如果執行錯誤回滾操作,但是如果程序里面已經有了事務回滾,那么存儲過程就不要寫事務了,這樣會導致事務回滾嵌套降低執行效率,但是我們很多時候可以把檢查放在存儲過程里,這樣有利于我們解讀這個存儲過程,和排錯。

view sourceprint?
BEGIN TRANSACTION?
--事務回滾開始??????
?
--檢查報錯
IF ( @@ERROR > 0 )????
??????????????????? BEGIN??????
--回滾操作
??????????????????????? ROLLBACK TRANSACTION??????
??????????????????????? RAISERROR('刪除工作報告錯誤', 16, 3)???????
??????????????????????? RETURN????????
??????????????????? END????????
?
?
--結束事務
? COMMIT TRANSACTION????

??????? 好久沒有寫博文了,工作項目一個接一個,再加上公司人員流動,新人很多事情接不下來,加班成了家常便飯,倉促寫下這些希望對大家有幫助,不對的也歡迎指點,交流互相提高。

轉載于:https://www.cnblogs.com/gaaraliang/archive/2011/11/18/2254266.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/380096.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/380096.shtml
英文地址,請注明出處:http://en.pswp.cn/news/380096.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

java上傳類

publicString doFormFile(FormFile file, String dir) { try { File f new File(dir); if (!f.exists()) { f.mkdir();//如果路徑不存在&#xff0c;創建 } InputStream in file.getInputStream(); …

C——用冒泡排序法、選擇排序法對隨機輸入的10個整數從小到大排序

//冒泡排序法 #include <stdio.h> int main() {int i,j,t,a[10];for(i0;i<10;i){scanf("%d",&a[i]);}for(i0;i<9;i)//10個數&#xff0c;進行9次循環&#xff0c;進行9趟比較{for(j0;j<9-i;j)//在每一趟比較中&#xff0c;進行9-i次比較{if(a[j]&…

遠控免殺專題(21)-HERCULES免殺

轉載&#xff1a;https://mp.weixin.qq.com/s/Rkr9lixzL4tiL89r10ndig 免殺能力一覽表 幾點說明&#xff1a; 1、上表中標識 √ 說明相應殺毒軟件未檢測出病毒&#xff0c;也就是代表了Bypass。 2、為了更好的對比效果&#xff0c;大部分測試payload均使用msf的windows/mete…

PHP Cookbook讀書筆記 – 第16章互聯網服務

發送電子郵件 書中主要是以PEAR中的郵件發送類&#xff08;Mail&#xff09;來講解的&#xff08;關于如何在WIN系統下安裝PEAR可以參考WIN下成功安裝PEAR&#xff09;。PEAR的MAIL類可以通過3種方式來發送電子郵件&#xff1a; 通過PHP內部的mail函數來發送 通過sendmail程序來…

Python | 使用matplotlib.pyplot創建條形圖

Problem statement: Using matplotlib.pyplot library in python draw a bar graph with two values for comparison, using different colors. 問題陳述&#xff1a;在python中使用matplotlib.pyplot庫使用不同的顏色繪制帶有兩個值的條形圖以進行比較。 Program: 程序&#…

SQLSERVER內核架構剖析

我們做管理軟件的&#xff0c;主要核心就在數據存儲管理上。所以數據庫設計是我們的重中之重。為了讓我們的管理軟件能夠穩定、可擴展、性能優秀、可跟蹤排錯、可升級部署、可插件運行&#xff0c;我們往往研發自己的管理軟件開發平臺。我們總是希望去學習別人的開發平臺&#…

輸出以下的楊輝三角形(要求輸入個數字,表示需要輸出幾行)

#include<stdio.h> int main() {int i,j,k,n,x,a[100][100];a[0][1]1;scanf("%d",&x);for(i1;i<x;i){for(j1;j<i;j){a[i][j]a[i-1][j-1]a[i-1][j];printf("%5d ",a[i][j]);//%5d 表示右對齊隔5個空格&#xff1b;}//同理&#xff0c;%-5d…

遠控免殺專題(22)-SpookFlare免殺

轉載&#xff1a;https://mp.weixin.qq.com/s/LfuQ2XuD7YHUWJqMRUmNVA 免殺能力一覽表 幾點說明&#xff1a; 1、上表中標識 √ 說明相應殺毒軟件未檢測出病毒&#xff0c;也就是代表了Bypass。 2、為了更好的對比效果&#xff0c;大部分測試payload均使用msf的windows/mete…

二維動態數組定義及二維靜態數組與**P的區別

矩力集成2008年校園招聘筆試題&#xff1a;動態申請一個二維數組存儲圖像陣列 傳統的解決方案是分配一個指針數組, 然后把每個指針初始化為動態分配的 列"。 以下為一個二維的例子: //typedef int (*arraypoiter)[ncolumns]; int **dynamic_alloc_arrays(unsigned int nro…

置換元素和非置換元素_循環置換數組元素的C程序

置換元素和非置換元素Problem statement: Write a c program to cyclically permute the element of an array. (In right to left direction). Array should be taken as input from the user. 問題陳述&#xff1a;編寫一個c程序來循環置換array的元素 。 (從右到左方向)。 數…

最新Asp.net源碼推薦列表(4月7日)

好久沒有在cnblogs給大家發布asp.net源碼了&#xff0c;把最近整理的一些發給大家&#xff0c;希望對大家有所幫助&#xff0c;以后爭取保持每周發布&#xff01;- WOBIZ第一季1.2版源碼 Hits:29 2008-4-7 [結構圖] [^][VS2005Access] 電子商務2.0軟件是窩窩團隊基于對互聯網…

遠控免殺專題(23)-SharpShooter免殺

轉載&#xff1a;https://mp.weixin.qq.com/s/EyvGfWXLbxkHe7liaNFhGg 免殺能力一覽表 幾點說明&#xff1a; 1、上表中標識 √ 說明相應殺毒軟件未檢測出病毒&#xff0c;也就是代表了Bypass。 2、為了更好的對比效果&#xff0c;大部分測試payload均使用msf的windows/mete…

MySQL 發展史

一.MySQL 標志說明MySQL的海豚標志的名字叫“sakila”&#xff0c;它是由MySQL AB的創始人從用戶在“海豚命名”的競賽中建議的大量的名字表中選出的。獲勝的名字是由來自非洲斯威士蘭的開源軟件開發者Ambrose Twebaze提供。根據Ambrose所說&#xff0c;Sakila來自一種叫SiSwat…

scanf讀取字符_在C語言中使用scanf()讀取整數時跳過字符

scanf讀取字符Let suppose, we want to read time in HH:MM:SS format and store in the variables hours, minutes and seconds, in that case we need to skip columns (:) from the input values. 假設&#xff0c;我們要讀取HH&#xff1a;MM&#xff1a;SS格式的時間 &…

An Algorithm Summary of Programming Collective Intelligence (3)

k-Nearest Neighbors kNN(不要問我叫什么)PCI里面用kNN做了一個價格預測模型&#xff0c;還有一個簡單的電影喜好預測。簡單來說就是要對一個東西做數值預測&#xff0c;就要先有一堆已經有數值的東西&#xff0c;從里面找出和要預測的東西相似的&#xff0c;再通過計算這些相似…

遠控免殺專題(24)-CACTUSTORCH免殺

轉載&#xff1a;https://mp.weixin.qq.com/s/g0CYvFMsrV7bHIfTnSUJBw 免殺能力一覽表 幾點說明&#xff1a; 1、上表中標識 √ 說明相應殺毒軟件未檢測出病毒&#xff0c;也就是代表了Bypass。 2、為了更好的對比效果&#xff0c;大部分測試payload均使用msf的windows/mete…

DOM快捷鍵

DOM所有的命令(CMD) 步驟/方法 cmd命令大全&#xff08;第一部分&#xff09;winver---------檢查Windows版本 wmimgmt.msc----打開windows管理體系結構(WMI) wupdmgr--------windows更新程序 wscript--------windows腳本宿主設置 write----------寫字板 winmsd---------系統…

病毒的手工排除與分析(更新完畢)

作者簡介楊京濤    8年以上的IT行業經驗&#xff0c;理解企業需求&#xff0c;有企業ERP軟件部署規劃能力&#xff0c;有綜合布線網絡規劃和管理能力。熟悉軟件以及各類硬件&#xff0c;電話程控設備&#xff0c;各類網絡設備的管理維護。有編程基礎,熟悉VBA、腳本、批處理…

JavaScript中的String substring()方法和示例

JavaScript | 字符串substring()方法 (JavaScript | String substring() Method) The String.substring() method in JavaScript is used to return a part of the string. The substring() extracted is from the given start and end index of the string. JavaScript中的Str…

Java——方法(練習九九乘法表)

public static void(int,byte…) xxx(int a,int b) 修飾符 返回值類型 方法名(參數類型 參數名1&#xff0c;參數類型 參數名2…)&#xff5b; 方法體語句&#xff1b; return 返回值&#xff1b; &#xff5d; public class fangfa {public static void main(String[] ar…