目錄
查詢的邏輯執行順序
##執行順序
#只傳回所需的資料
#注意臨時表和表變量的用法
都盡量使用索引
多表連接與索引
其他
二執行順序:
三、只回傳需要的資料
A、控制同一語句的多次執行,特別是一些基礎資料的多次執行是許多程式設計師很少注意的。
五、注意临时表和表变量的用法
六、子查询的用法(1)
七:尽量使用索引
八. 多表连接条件与索引选择
九. 其它
首頁 資料庫 mysql教程 詳細介紹SQL程式設計的一些好習慣

詳細介紹SQL程式設計的一些好習慣

Mar 06, 2017 pm 01:14 PM
sql

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

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

 以下是個人認為的SQL程式設計的一些好習慣:

  1. 查詢的邏輯執行順序

  2. ##執行順序

  3. #只傳回所需的資料

  4. #盡量少做重複的工作

  5. #注意臨時表和表變量的用法

  6. 子查詢的用法

  7. 都盡量使用索引

  8. 多表連接與索引

  9. 其他

 

#一:查詢的邏輯執行順序
(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歧義引起的語法錯誤。

如有表table1(ID,col1)和table2 (ID,col2)

 Select A.ID, A.col1, B.col2
 
 -- Select A.ID, col1, col2 –不要这么写,不利于将来程序扩展
 
from table1 A inner join table2 B on A.ID=B.ID Where …
登入後複製

 B、縱向來看:##(1)合理寫WHERE子句,不要寫沒有WHERE的SQL語句。

(2) SELECT TOP N * --沒有WHERE條件的用此替代 

四:盡量少做重複的工作

A、控制同一語句的多次執行,特別是一些基礎資料的多次執行是許多程式設計師很少注意的。

B、減少多次的資料轉換,也許需要資料轉換是設計的問題,但是減少次數是程式設計師可以做到的。

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

D、合并对同一表同一条件的多次UPDATE,比如

UPDATE EMPLOYEE SET FNAME=&#39;HAIWER&#39;
WHERE EMP_ID=&#39; VPA30890F&#39; UPDATE EMPLOYEE SET LNAME=&#39;YANG&#39;
WHERE EMP_ID=&#39; VPA30890F&#39;
登入後複製

这两个语句应该合并成以下一个语句

UPDATE EMPLOYEE SET FNAME=&#39;HAIWER&#39;,LNAME=&#39;YANG&#39;  WHERE EMP_ID=&#39; VPA30890F&#39;
登入後複製

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)

SELECT TITLE FROM TITLES 
WHERE NOT EXISTS 
 (SELECT TITLE_ID FROM SALES 
WHERE TITLE_ID = TITLES.TITLE_ID)
登入後複製

可以改写成:

SELECT TITLE 
FROM TITLES LEFT JOIN SALES 
ON SALES.TITLE_ID = TITLES.TITLE_ID 
WHERE SALES.TITLE_ID IS NULL
登入後複製

B、 如果保证子查询没有重复 ,IN、EXISTS的相关子查询可以用INNER JOIN 代替。比如:

SELECT PUB_NAME 
FROM PUBLISHERS 
WHERE PUB_ID IN
 (SELECT PUB_ID 
 FROM TITLES 
 WHERE TYPE = &#39;BUSINESS&#39;)
登入後複製

可以改写成:

SELECT A.PUB_NAME --SELECT DISTINCT A.PUB_NAME 
FROM PUBLISHERS A INNER JOIN TITLES B 
ON        B.TYPE = &#39;BUSINESS&#39; AND
A.PUB_ID=B. PUB_ID
登入後複製

(3)

C、 IN的相关子查询用EXISTS代替,比如

SELECT PUB_NAME FROM PUBLISHERS 
WHERE PUB_ID IN
(SELECT PUB_ID FROM TITLES WHERE TYPE = &#39;BUSINESS&#39;)
登入後複製

可以用下面语句代替:

SELECT PUB_NAME FROM PUBLISHERS WHERE EXISTS 
(SELECT 1 FROM TITLES WHERE TYPE = &#39;BUSINESS&#39; AND
PUB_ID= PUBLISHERS.PUB_ID)
登入後複製

D、不要用COUNT(*)的子查询判断是否存在记录,最好用LEFT JOIN或者EXISTS,比如有人写这样的语句:

SELECT JOB_DESC FROM JOBS 
WHERE (SELECT COUNT(*) FROM EMPLOYEE WHERE JOB_ID=JOBS.JOB_ID)=0
登入後複製

应该改成:

SELECT JOBS.JOB_DESC FROM JOBS LEFT JOIN EMPLOYEE  
ON EMPLOYEE.JOB_ID=JOBS.JOB_ID 
WHERE EMPLOYEE.EMP_ID IS NULL
  
SELECT JOB_DESC FROM JOBS 
WHERE (SELECT COUNT(*) FROM EMPLOYEE WHERE JOB_ID=JOBS.JOB_ID)<>0
登入後複製

应该改成:

SELECT JOB_DESC FROM JOBS 
WHERE EXISTS (SELECT 1 FROM EMPLOYEE WHERE JOB_ID=JOBS.JOB_ID)
登入後複製

七:尽量使用索引

建立索引后,并不是每个查询都会使用索引,在使用索引的情况下,索引的使用效率也会有很大的差别。只要我们在查询语句中没有强制指定索引,

索引的选择和使用方法是SQLSERVER的优化器自动作的选择,而它选择的根据是查询语句的条件以及相关表的统计信息,这就要求我们在写SQL

语句的时候尽量使得优化器可以使用索引。为了使得优化器能高效使用索引,写语句的时候应该注意:

(1)

A、不要对索引字段进行运算,而要想办法做变换,比如

SELECT ID FROM T WHERE NUM/2=100
登入後複製

应改为:

SELECT ID FROM T WHERE NUM=100*2
SELECT ID FROM T WHERE NUM/2=NUM1
登入後複製

如果NUM有索引应改为:

SELECT ID FROM T WHERE NUM=NUM1*2
登入後複製

如果NUM1有索引则不应该改。

(2)

发现过这样的语句:

SELECT 年,月,金额 FROM 结余表  WHERE 100*年+月=2010*100+10
登入後複製

应该改为:

SELECT 年,月,金额 FROM 结余表 WHERE 年=2010 AND月=10
登入後複製

B、 不要对索引字段进行格式转换

日期字段的例子:

WHERE CONVERT(VARCHAR(10), 日期字段,120)=&#39;2010-07-15&#39;
登入後複製

应该改为

WHERE日期字段〉=&#39;2010-07-15&#39;   AND   日期字段<&#39;2010-07-16&#39;
登入後複製

ISNULL转换的例子:

WHERE ISNULL(字段,&#39;&#39;)<>&#39;&#39;应改为:WHERE字段<>&#39;&#39;
WHERE ISNULL(字段,&#39;&#39;)=&#39;&#39;不应修改
WHERE ISNULL(字段,&#39;F&#39;) =&#39;T&#39;应改为: WHERE字段=&#39;T&#39;
WHERE ISNULL(字段,&#39;F&#39;)<>&#39;T&#39;不应修改
登入後複製

(3)

C、 不要对索引字段使用函数

WHERE LEFT(NAME, 3)=&#39;ABC&#39; 或者WHERE SUBSTRING(NAME,1, 3)=&#39;ABC&#39;
登入後複製

应改为: WHERE NAME LIKE 'ABC%'

日期查询的例子:

WHERE DATEDIFF(DAY, 日期,&#39;2010-06-30&#39;)=0
登入後複製

应改为:

WHERE 日期>=&#39;2010-06-30&#39; AND 日期 <&#39;2010-07-01&#39;
登入後複製
WHERE DATEDIFF(DAY, 日期,&#39;2010-06-30&#39;)>0
登入後複製

应改为:

WHERE 日期 <&#39;2010-06-30&#39;
登入後複製
WHERE DATEDIFF(DAY, 日期,&#39;2010-06-30&#39;)>=0
登入後複製

应改为:

WHERE 日期 <&#39;2010-07-01&#39;
登入後複製
WHERE DATEDIFF(DAY, 日期,&#39;2010-06-30&#39;)<0
登入後複製

应改为:

WHERE 日期>=&#39;2010-07-01&#39;
登入後複製
WHERE DATEDIFF(DAY, 日期,&#39;2010-06-30&#39;)<=0
登入後複製

应改为:

WHERE 日期>=&#39;2010-06-30&#39;
登入後複製

D、不要对索引字段进行多字段连接

比如:

WHERE FAME+ &#39;. &#39;+LNAME=&#39;HAIWEI.YANG&#39;
登入後複製

应改为:

WHERE FNAME=&#39;HAIWEI&#39; AND LNAME=&#39;YANG&#39;
登入後複製

八. 多表连接条件与索引选择

A、多表连接的时候,连接条件必须写全,宁可重复,不要缺漏。

B、连接条件尽量使用聚集索引

C、注意ON、WHERE和HAVING部分条件的区别

ON是最先执行, WHERE次之,HAVING最后,因为ON是先把不符合条件的记录过滤后才进行统计,它就可以减少中间运算要处理的数据,按理说应该速度是最快的,WHERE也应该比 HAVING快点的,因为它过滤数据后才进行SUM,在两个表联接时才用ON的,所以在一个表的时候,就剩下WHERE跟HAVING比较了

考虑联接优先顺序:

(1)INNER JOIN
(2)LEFT JOIN (注:RIGHT JOIN 用 LEFT JOIN 替代)
(3)CROSS JOIN
登入後複製

九. 其它

A、在IN后面值的列表中,将出现最频繁的值放在最前面,出现得最少的放在最后面,减少判断的次数

B、注意UNION和UNION ALL的区别。--允许重复数据用UNION ALL好

C、注意使用DISTINCT,在没有必要时不要用

D、TRUNCATE TABLE 与 DELETE 区别

E、减少访问数据库的次数

还有就是我们写存储过程,如果比较长的话,最后用标记符标开,因为这样可读性很好,即使语句写的不怎么样但是语句工整,C# 有region

sql我比较喜欢用的就是

--startof 查询在职人数

sql语句

--end of

正式机器上我们一般不能随便调试程序,但是很多时候程序在我们本机上没问题,但是进正式系统就有问题,但是我们又不能随便在正式机器上操作,那么怎么办呢?我们可以用回滚来调试我们的存储过程或者是sql语句,从而排错。

BEGIN TRAN
 UPDATE a SET 字段=&#39;&#39;
ROLLBACK
登入後複製

作业存储过程我一般会加上下面这段,这样检查错误可以放在存储过程,如果执行错误回滚操作,但是如果程序里面已经有了事务回滚,那么存储过程就不要写事务了,这样会导致事务回滚嵌套降低执行效率,但是我们很多时候可以把检查放在存储过程里,这样有利于我们解读这个存储过程,和排错。

BEGIN TRANSACTION
登入後複製

--事务回滚开始

--检查报错

 IF ( @@ERROR > 0 )     
        BEGIN
登入後複製

--回滚操作

ROLLBACK TRANSACTION       
RAISERROR(&#39;删除工作报告错误&#39;, 16, 3)        
     RETURN         
      END
登入後複製

--结束事务

  COMMIT TRANSACTION
登入後複製

        以上就是详细介绍SQL编程的一些良好好习惯的内容,更多相关内容请关注PHP中文网(www.php.cn)!


本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它們
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

Hibernate 框架中 HQL 和 SQL 的差異是什麼? Hibernate 框架中 HQL 和 SQL 的差異是什麼? Apr 17, 2024 pm 02:57 PM

HQL和SQL在Hibernate框架中進行比較:HQL(1.物件導向語法,2.資料庫無關的查詢,3.類型安全),而SQL直接操作資料庫(1.與資料庫無關的標準,2.可執行複雜查詢和資料操作)。

Oracle SQL中除法運算的用法 Oracle SQL中除法運算的用法 Mar 10, 2024 pm 03:06 PM

《OracleSQL中除法運算的用法》在OracleSQL中,除法運算是常見的數學運算之一。在資料查詢和處理過程中,除法運算可以幫助我們計算欄位之間的比例或得出特定數值的邏輯關係。本文將介紹OracleSQL中除法運算的用法,並提供具體的程式碼範例。一、OracleSQL中除法運算的兩種方式在OracleSQL中,除法運算可以用兩種不同的方式來進行

Oracle與DB2的SQL語法比較與區別 Oracle與DB2的SQL語法比較與區別 Mar 11, 2024 pm 12:09 PM

Oracle和DB2是兩個常用的關聯式資料庫管理系統,它們都有自己獨特的SQL語法和特性。本文將針對Oracle和DB2的SQL語法進行比較與區別,並提供具體的程式碼範例。資料庫連接在Oracle中,使用以下語句連接資料庫:CONNECTusername/password@database而在DB2中,連接資料庫的語句如下:CONNECTTOdataba

詳解MyBatis動態SQL標籤中的Set標籤功能 詳解MyBatis動態SQL標籤中的Set標籤功能 Feb 26, 2024 pm 07:48 PM

MyBatis動態SQL標籤解讀:Set標籤用法詳解MyBatis是一個優秀的持久層框架,它提供了豐富的動態SQL標籤,可以靈活地建構資料庫操作語句。其中,Set標籤是用來產生UPDATE語句中SET子句的標籤,在更新作業中非常常用。本文將詳細解讀MyBatis中Set標籤的用法,以及透過具體的程式碼範例來示範其功能。什麼是Set標籤Set標籤用於MyBati

SQL中的identity屬性是什麼意思? SQL中的identity屬性是什麼意思? Feb 19, 2024 am 11:24 AM

SQL中的Identity是什麼,需要具體程式碼範例在SQL中,Identity是一種用於產生自增數字的特殊資料類型,它常用於唯一識別表中的每一行資料。 Identity欄位通常與主鍵列搭配使用,可確保每筆記錄都有獨一無二的識別碼。本文將詳細介紹Identity的使用方式以及一些實際的程式碼範例。 Identity的基本使用方式在建立表格時,可以使用Identit

Springboot+Mybatis-plus不使用SQL語句進行多表新增怎麼實現 Springboot+Mybatis-plus不使用SQL語句進行多表新增怎麼實現 Jun 02, 2023 am 11:07 AM

在Springboot+Mybatis-plus不使用SQL語句進行多表添加操作我所遇到的問題準備工作在測試環境下模擬思維分解一下:創建出一個帶有參數的BrandDTO對像模擬對後台傳遞參數我所遇到的問題我們都知道,在我們使用Mybatis-plus中進行多表操作是極其困難的,如果你不使用Mybatis-plus-join這一類的工具,你只能去配置對應的Mapper.xml文件,配置又臭又長的ResultMap,然後再寫對應的sql語句,這種方法雖然看上去很麻煩,但具有很高的靈活性,可以讓我們

SQL出現5120錯誤怎麼解決 SQL出現5120錯誤怎麼解決 Mar 06, 2024 pm 04:33 PM

解決方法:1、檢查登入使用者是否具有足夠的權限來存取或操作該資料庫,確保該使用者俱有正確的權限;2、檢查SQL Server服務的帳戶是否具有存取指定檔案或資料夾的權限,確保該帳戶具有足夠的權限來讀取和寫入該文件或資料夾;3、檢查指定的資料庫文件是否已被其他進程打開或鎖定,嘗試關閉或釋放該文件,並重新運行查詢;4、嘗試以管理員身份運行Management Studio等等。

如何使用SQL語句在MySQL中進行資料聚合和統計? 如何使用SQL語句在MySQL中進行資料聚合和統計? Dec 17, 2023 am 08:41 AM

如何使用SQL語句在MySQL中進行資料聚合和統計?在進行資料分析和統計時,資料聚合和統計是非常重要的步驟。 MySQL作為一個功能強大的關聯式資料庫管理系統,提供了豐富的聚合和統計函數,可以很方便地進行資料聚合和統計操作。本文將介紹使用SQL語句在MySQL中進行資料聚合和統計的方法,並提供具體的程式碼範例。一、使用COUNT函數進行計數COUNT函數是最常用

See all articles