精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

SQL點滴之性能優化其實沒有那么神秘

數據庫 SQL Server 數據庫運維
始終認為,一個系統的性能的提高,不單單是試運行或者維護階段的性能調優的任務,也不單單是開發階段的事情,而是在整個軟件生命周期都需要注意,進行有效工作才能達到的。所以作者希望按照軟件生命周期的不同階段來總結數據庫性能優化相關的注意事項。

經常聽說SQL Server最難的部分是性能優化,不禁讓人感到優化這個工作很神秘,這種事情只有高手才能做。很早的時候我在網上看到一位高手寫的博客,介紹了SQL優化的問題,從這些內容來看,優化并不都是一些很復雜的問題,掌握了基本的知識之后也可以嘗試優化自己的SQL程序,甚至是其他相關的程序。優化是一些工作積累之后的經驗總結和代碼意識,只要平時注意積累,你也可以做優化的工作。這一篇隨筆是轉載,不過我強烈推薦給所有對數據庫優化有興趣的博友,讀了這一篇之后下一次別人談論優化的時候我們這些小菜就可以跟別人侃侃而談了,不至于面面相覷,不知所措。首先給出地址:http://blog.csdn.net/haiwer/article/details/2826881

始終認為,一個系統的性能的提高,不單單是試運行或者維護階段的性能調優的任務,也不單單是開發階段的事情,而是在整個軟件生命周期都需要注意,進行有效工作才能達到的。所以我希望按照軟件生命周期的不同階段來總結數據庫性能優化相關的注意事項。

一、分析階段

一般來說,在系統分析階段往往有太多需要關注的地方,系統各種功能性、可用性、可靠性、安全性需求往往吸引了我們大部分的注意力,但是,我們必須注意,性能是很重要的非功能性需求,必須根據系統的特點確定其實時性需求、響應時間的需求、硬件的配置等。***能有各種需求的量化的指標。另一方面,在分析階段應該根據各種需求區分出系統的類型,大的方面,區分是OLTP(聯機事務處理系統)和OLAP(聯機分析處理系統)。

二、設計階段

設計階段可以說是以后系統性能的關鍵階段,在這個階段,有一個關系到以后幾乎所有性能調優的過程—數據庫設計。在數據庫設計完成后,可以進行初步的索引設計,好的索引設計可以指導編碼階段寫出高效率的代碼,為整個系統的性能打下良好的基礎。

以下是性能要求設計階段需要注意的:

1、數據庫邏輯設計的規范化

數據庫邏輯設計的規范化就是我們一般所說的范式,我們可以這樣來簡單理解范式:

第1規范:沒有重復的組或多值的列,就是一個表中的列不可再分,這是數據庫設計的***要求。

第2規范: 每個非關鍵字段必須依賴于主關鍵字,不能依賴于一個組合式主關鍵字的某些組成部分。就是說一個表中的行可以唯一標識。消除

部分依賴,大部分情況下,數據庫設計都應該達到第二范式。

第3規范: 一個非關鍵字段不能依賴于另一個非關鍵字段。消除傳遞依賴,達到第三范式應該是系統中大部分表的要求,除非一些特殊作用的表。

更高的范式要求這里就不再作介紹了,個人認為,如果全部達到第二范式,大部分達到第三范式,系統會產生較少的列和較多的表,因而減少了數據冗余,也利于性能的提高。

2、合理的冗余

完全按照規范化設計的系統幾乎是不可能的,除非系統特別的小,在規范化設計后,有計劃地加入冗余是必要的。

冗余可以是冗余數據庫、冗余表或者冗余字段,不同粒度的冗余可以起到不同的作用。

冗余可以是為了編程方便而增加,也可以是為了性能的提高而增加。從性能角度來說,冗余數據庫可以分散數據庫壓力,冗余表可以分散數據量大的表的并發壓力,也可以加快特殊查詢的速度,冗余字段可以有效減少數據庫表的連接,提高效率。

3、主鍵的設計

主鍵是必要的,SQL SERVER的主鍵同時是一個唯一索引,而且在實際應用中,我們往往選擇最小的鍵組合作為主鍵,所以主鍵往往適合作為表的聚集索引。聚集索引對查詢的影響是比較大的,這個在下面索引的敘述。

在有多個鍵的表,主鍵的選擇也比較重要,一般選擇總的長度小的鍵,小的鍵的比較速度快,同時小的鍵可以使主鍵的B樹結構的層次更少。主鍵的選擇還要注意組合主鍵的字段次序,對于組合主鍵來說,不同的字段次序的主鍵的性能差別可能會很大,一般應該選擇重復率低、單獨或者組合查詢可能性大的字段放在前面。

4、外鍵的設計

外鍵作為數據庫對象,很多人認為麻煩而不用,實際上,外鍵在大部分情況下是很有用的,理由是:外鍵是***效的一致性維護方法,數據庫的一致性要求,依次可以用外鍵、CHECK約束、規則約束、觸發器、客戶端程序,一般認為,離數據越近的方法效率越高。

謹慎使用級聯刪除和級聯更新,級聯刪除和級聯更新作為SQL SERVER 2000當年的新功能,在2005作了保留,應該有其可用之處。我這里說的謹慎,是因為級聯刪除和級聯更新有些突破了傳統的關于外鍵的定義,功能有點太過強大,使用前必須確定自己已經把握好其功能范圍,否則,級聯刪除和級聯更新可能讓你的數據莫名其妙的被修改或者丟失。從性能看級聯刪除和級聯更新是比其他方法更高效的方法。

5、字段的設計

字段是數據庫最基本的單位,其設計對性能的影響是很大的。需要注意如下:

  • 數據類型盡量用數字型,數字型的比較比字符型的快很多。
  • 數據類型盡量小,這里的盡量小是指在滿足可以預見的未來需求的前提下的。
  • 盡量不要允許NULL,除非必要,可以用NOT NULL+DEFAULT代替。
  • 少用TEXT和IMAGE,二進制字段的讀寫是比較慢的,而且,讀取的方法也不多,大部分情況下***不用。
  • 自增字段要慎用,不利于數據遷移。

6、數據庫物理存儲和環境的設計

在設計階段,可以對數據庫的物理存儲、操作系統環境、網絡環境進行必要的設計,使得我們的系統在將來能適應比較多的用戶并發和比較大的數據量。這里需要注意文件組的作用,適用文件組可以有效把I/O操作分散到不同的物理硬盤,提高并發能力。

7、系統設計

整個系統的設計特別是系統結構設計對性能是有很大影響的,對于一般的OLTP系統,可以選擇C/S結構、三層的C/S結構等,不同的系統結構其性能的關鍵也有所不同。

系統設計階段應該歸納一些業務邏輯放在數據庫編程實現,數據庫編程包括數據庫存儲過程、觸發器和函數。用數據庫編程實現業務邏輯的好處是減少網絡流量并可更充分利用數據庫的預編譯和緩存功能。

8、索引的設計

在設計階段,可以根據功能和性能的需求進行初步的索引設計,這里需要根據預計的數據量和查詢來設計索引,可能與將來實際使用的時候會有所區別。

關于索引的選擇,應改主意:

  • 根據數據量決定哪些表需要增加索引,數據量小的可以只有主鍵。
  • 根據使用頻率決定哪些字段需要建立索引,選擇經常作為連接條件、篩選條件、聚合查詢、排序的字段作為索引的候選字段。
  • 把經常一起出現的字段組合在一起,組成組合索引,組合索引的字段順序與主鍵一樣,也需要把最常用的字段放在前面,把重復率低的字段放在前面。
  • 一個表不要加太多索引,因為索引影響插入和更新的速度。

#p#

三、編碼階段

編碼階段是本文的重點,因為在設計確定的情況下,編碼的質量幾乎決定了整個系統的質量。

編碼階段首先是需要所有程序員有性能意識,也就是在實現功能同時有考慮性能的思想,數據庫是能進行集合運算的工具,我們應該盡量的利用這個工具,所謂集合運算實際是批量運算,就是盡量減少在客戶端進行大數據量的循環操作,而用SQL語句或者存儲過程代替。關于思想和意識,很難說得很清楚,需要在編程過程中來體會。

下面羅列一些編程階段需要注意的事項:

1、只返回需要的數據

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

A、橫向來看,不要寫SELECT *的語句,而是選擇你需要的字段。

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

C、注意SELECT INTO后的WHERE子句,因為SELECT INTO把數據插入到臨時表,這個過程會鎖定一些系統表,如果這個WHERE子句返回的數據過多或者速度太慢,會造成系統表長期鎖定,諸塞其他進程。

D、對于聚合查詢,可以用HAVING子句進一步限定返回的行。

2、盡量少做重復的工作

這一點和上一點的目的是一樣的,就是盡量減少無效工作,但是這一點的側重點在客戶端程序,需要注意的如下:

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

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

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

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

  1. UPDATE EMPLOYEE SET FNAME=’HAIWER’ WHERE EMP_ID=’ VPA30890F’ 
  2. UPDATE EMPLOYEE SET LNAME=’YANG’ WHERE EMP_ID=’ VPA30890F’ 

這兩個語句應該合并成以下一個語句

  1. UPDATE EMPLOYEE SET FNAME=’HAIWER’,LNAME=’YANG’ 
  2. WHERE EMP_ID=’ VPA30890F’ 

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

F、不要寫一些沒有意義的查詢,比如: SELECT * FROM EMPLOYEE WHERE 1=2

3、注意事務和鎖

事務是數據庫應用中和重要的工具,它有原子性、一致性、隔離性、持久性這四個屬性,很多操作我們都需要利用事務來保證數據的正確性。在使用事務中我們需要做到盡量避免死鎖、盡量減少阻塞。具體以下方面需要特別注意:

A、事務操作過程要盡量小,能拆分的事務要拆分開來。

B、事務操作過程不應該有交互,因為交互等待的時候,事務并未結束,可能鎖定了很多資源。

C、事務操作過程要按同一順序訪問對象。

D、提高事務中每個語句的效率,利用索引和其他方法提高每個語句的效率可以有效地減少整個事務的執行時間。

E、盡量不要指定鎖類型和索引,SQL SERVER允許我們自己指定語句使用的鎖類型和索引,但是一般情況下,SQL SERVER優化器選擇的鎖類型和索引是在當前數據量和查詢條件下是***的,我們指定的可能只是在目前情況下更有,但是數據量和數據分布在將來是會變化的。

F、查詢時可以用較低的隔離級別,特別是報表查詢的時候,可以選擇***的隔離級別(未提交讀)。

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

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

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

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

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

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

E、關于臨時表和表變量的選擇,很多說法是表變量在內存,速度快,應該***表變量,但是在實際使用中發現,這個選擇主要考慮需要放在臨時表的數據量,在數據量較多的情況下,臨時表的速度反而更快。

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。

G、注意排序規則,用CREATE TABLE建立的臨時表,如果不指定字段的排序規則,會選擇TEMPDB的默認排序規則,而不是當前數據庫的排序規則。如果當前數據庫的排序規則和 TEMPDB的排序規則不同,連接的時候就會出現排序規則的沖突錯誤。一般可以在CREATE TABLE建立臨時表時指定字段的排序規則為DATABASE_DEFAULT來避免上述問題。

#p#

5、 子查詢的用法

子查詢是一個 SELECT 查詢,它嵌套在 SELECT、INSERT、UPDATE、DELETE 語句或其它子查詢中。任何允許使用表達式的地方都可以使用子查詢。

子查詢可以使我們的編程靈活多樣,可以用來實現一些特殊的功能。但是在性能上,往往一個不合適的子查詢用法會形成一個性能瓶頸。如果子查詢的條件中使用了其外層的表的字段,這種子查詢就叫作相關子查詢。相關子查詢可以用IN、NOT IN、EXISTS、NOT EXISTS引入。

關于相關子查詢,應該注意:

A、NOT IN、NOT EXISTS的相關子查詢可以改用LEFT JOIN代替寫法。比如:

  1. SELECT PUB_NAME 
  2. FROM PUBLISHERS 
  3. WHERE PUB_ID NOT IN 
  4.    (SELECT PUB_ID 
  5.    FROM TITLES 
  6.    WHERE TYPE = 'BUSINESS'
  7.             可以改寫成: 
  8.  
  9. SELECT A.PUB_NAME 
  10. FROM PUBLISHERS A LEFT JOIN TITLES B 
  11. ON        B.TYPE = 'BUSINESS' AND 
  12.           A.PUB_ID=B.PUB_ID 
  13. WHERE B.PUB_ID IS NULL 
  14.   
  15.  
  16. SELECT TITLE 
  17. FROM TITLES 
  18. WHERE NOT EXISTS 
  19.    (SELECT TITLE_ID 
  20.    FROM SALES 
  21.    WHERE TITLE_ID = TITLES.TITLE_ID) 
  22.  
  23. 可以改寫成: 
  24.  
  25. SELECT TITLE 
  26. FROM TITLES LEFT JOIN SALES 
  27. ON SALES.TITLE_ID = TITLES.TITLE_ID 
  28. WHERE SALES.TITLE_ID IS NULL 

B、 如果保證子查詢沒有重復 ,IN、EXISTS的相關子查詢可以用INNER JOIN 代替。比如:

  1. SELECT PUB_NAME 
  2. FROM PUBLISHERS 
  3. WHERE PUB_ID IN 
  4.    (SELECT PUB_ID 
  5.    FROM TITLES 
  6.    WHERE TYPE = 'BUSINESS'
  7.  
  8. 可以改寫成: 
  9.  
  10. SELECT DISTINCT A.PUB_NAME 
  11. FROM PUBLISHERS A INNER JOIN TITLES B 
  12. ON        B.TYPE = 'BUSINESS' AND 
  13.           A.PUB_ID=B.PUB_ID 

C、 IN的相關子查詢用EXISTS代替,比如

  1. SELECT PUB_NAME 
  2. FROM PUBLISHERS 
  3. WHERE PUB_ID IN 
  4.    (SELECT PUB_ID 
  5.    FROM TITLES 
  6.    WHERE TYPE = 'BUSINESS'
  7.  
  8. 可以用下面語句代替: 
  9.  
  10. SELECT PUB_NAME 
  11. FROM PUBLISHERS 
  12. WHERE EXISTS 
  13.    (SELECT 1 
  14.    FROM TITLES 
  15.    WHERE TYPE = 'BUSINESS' AND 
  16.    PUB_ID= PUBLISHERS.PUB_ID) 

D、不要用COUNT(*)的子查詢判斷是否存在記錄,***用LEFT JOIN或者EXISTS,比如有人寫這樣的語句:

  1. SELECT JOB_DESC FROM JOBS 
  2. WHERE (SELECT COUNT(*) FROM EMPLOYEE WHERE JOB_ID=JOBS.JOB_ID)=0 
  3.  
  4. 應該改成: 
  5.  
  6. SELECT JOBS.JOB_DESC FROM JOBS LEFT JOIN EMPLOYEE  
  7. ON EMPLOYEE.JOB_ID=JOBS.JOB_ID 
  8. WHERE EMPLOYEE.EMP_ID IS NULL 
  9.   
  10.  
  11. SELECT JOB_DESC FROM JOBS 
  12. WHERE (SELECT COUNT(*) FROM EMPLOYEE WHERE JOB_ID=JOBS.JOB_ID)<>0 
  13.  
  14. 應該改成: 
  15.  
  16. SELECT JOB_DESC FROM JOBS 
  17. WHERE EXISTS (SELECT 1 FROM EMPLOYEE WHERE JOB_ID=JOBS.JOB_ID) 

#p#

6、慎用游標

數據庫一般的操作是集合操作,也就是對由WHERE子句和選擇列確定的結果集作集合操作,游標是提供的一個非集合操作的途徑。一般情況下,游標實現的功能往往相當于客戶端的一個循環實現的功能,所以,大部分情況下,我們把游標功能搬到客戶端。

游標是把結果集放在服務器內存,并通過循環一條一條處理記錄,對數據庫資源(特別是內存和鎖資源)的消耗是非常大的,所以,我們應該只有在沒有其他方法的情況下才使用游標。

另外,我們可以用SQL SERVER的一些特性來代替游標,達到提高速度的目的。

A、字符串連接的例子

這是論壇經常有的例子,就是把一個表符合條件的記錄的某個字符串字段連接成一個變量。比如需要把JOB_ID=10的EMPLOYEE的FNAME連接在一起,用逗號連接,可能最容易想到的是用游標:

  1.  DECLARE @NAME VARCHAR(20) 
  2.  DECLARE @NAME VARCHAR(1000) 
  3.  DECLARE NAME_CURSOR CURSOR FOR 
  4.  SELECT FNAME FROM EMPLOYEE WHERE JOB_ID=10 ORDER BY EMP_ID 
  5.  OPEN NAME_CURSOR 
  6.  FETCH NEXT FROM RNAME_CURSOR INTO @NAME 
  7.  WHILE @@FETCH_STATUS = 0 
  8.  BEGIN 
  9.    SET @NAMES = ISNULL(@NAMES+’,’,’’)+@NAME 
  10.    FETCH NEXT FROM NAME_CURSOR  INTO @NAME  
  11.  END 
  12.  CLOSE NAME_CURSOR 
  13.  DEALLOCATE NAME_CURSOR 
  14. 下修改,功能相同: 
  15.  
  16. DECLARE @NAME VARCHAR(1000) 
  17. SELECT @NAMES = ISNULL(@NAMES+’,’,’’)+FNAME 
  18.    FROM EMPLOYEE WHERE JOB_ID=10 ORDER BY EMP_ID 

B、 用CASE WHEN 實現轉換的例子

很多使用游標的原因是因為有些處理需要根據記錄的各種情況需要作不同的處理,實際上這種情況,我們可以用CASE WHEN語句進行必要的判斷處理,而且CASE WHEN是可以嵌套的。比如:

表結構:

  1. CREATE TABLE 料件表( 
  2. 料號           VARCHAR(30), 
  3. 名稱           VARCHAR(100), 
  4. 主單位         VARCHAR(20), 
  5. 單位1         VARCHAR(20), 
  6. 單位1參數      NUMERIC(18,4), 
  7. 單位2         VARCHAR(20), 
  8. 單位2參數      NUMERIC(18,4) 
  9.  
  10. GO 
  11.  
  12. CREATE TABLE 入庫表( 
  13. 時間               DATETIME, 
  14. 料號               VARCHAR(30), 
  15. 單位               INT
  16. 入庫數量           NUMERIC(18,4), 
  17. 損壞數量           NUMERIC(18,4) 
  18.  
  19. GO 

其中,單位字段可以是0,1,2,分別代表主單位、單位1、單位2,很多計算需要統一單位,統一單位可以用游標實現:

  1. DECLARE @料號     VARCHAR(30), 
  2.         @單位   INT
  3.         @參數      NUMERIC(18,4), 
  4.  
  5. DECLARE CUR CURSOR FOR 
  6.         SELECT 料號,單位 FROM 入庫表 WHERE 單位 <>0 
  7. OPEN CUR 
  8. FETCH NEXT FROM CUR INTO @料號,@單位 
  9. WHILE @@FETCH_STATUS<>-1 
  10. BEGIN 
  11.   IF @單位=1 
  12.   BEGIN 
  13.     SET @參數=(SELECT 單位1參數 FROM 料件表 WHERE 料號 =@料號) 
  14.     UPDATE 入庫表 SET 數量=數量*@參數,損壞數量=損壞數量*@參數,單位=1 WHERE CURRENT OF CUR 
  15.   END 
  16.   IF @單位=2 
  17.   BEGIN 
  18.     SET @參數=(SELECT 單位1參數 FROM 料件表 WHERE 料號 =@料號) 
  19.     UPDATE 入庫表 SET 數量=數量*@參數,損壞數量=損壞數量*@參數,單位=1 WHERE CURRENT OF CUR 
  20.   END 
  21.   FETCH NEXT FROM CUR INTO @料號,@單位 
  22. END 
  23. CLOSE CUR 
  24. DEALLOCATE CUR 
  25.                             可以改寫成: 
  26.  
  27. UPDATE A SET  
  28. 數量=CASE A.單位 WHEN 1 THEN      A.數量*B. 單位1參數 
  29.                    WHEN 2 THEN         A.數量*B. 單位2參數 
  30.                    ELSE A.數量 
  31. END,                   
  32. 損壞數量= CASE A.單位 WHEN 1 THEN    A. 損壞數量*B. 單位1參數 
  33.                    WHEN 2 THEN         A. 損壞數量*B. 單位2參數 
  34.                    ELSE A. 損壞數量 
  35. END
  36. 單位=1  
  37. FROM入庫表 A, 料件表 B 
  38. WHERE    A.單位<>1      AND   A.料號=B.料號 

C、 變量參與的UPDATE語句的例子

SQL ERVER的語句比較靈活,變量參與的UPDATE語句可以實現一些游標一樣的功能,比如:

  1. SELECT A,B,C,CAST(NULL AS INTAS 序號 
  2. INTO #T 
  3. FROM 表 
  4. ORDER BY A ,NEWID() 

產生臨時表后,已經按照A字段排序,但是在A相同的情況下是亂序的,這時如果需要更改序號字段為按照A字段分組的記錄序號,就只有游標和變量參與的UPDATE語句可以實現了,這個變量參與的UPDATE語句如下:

  1. DECLARE @A INT 
  2. DECLARE @序號 INT 
  3. UPDATE #T SET 
  4.    @序號=CASE WHEN A=@A THEN @序號+1 ELSE 1 END
  5.    @A=A, 
  6.    序號=@序號 

D、如果必須使用游標,注意選擇游標的類型,如果只是循環取數據,那就應該用只進游標(選項FAST_FORWARD),一般只需要靜態游標(選項STATIC)。

E、 注意動態游標的不確定性,動態游標查詢的記錄集數據如果被修改,會自動刷新游標,這樣使得動態游標有了不確定性,因為在多用戶環境下,如果其他進程或者本身更改了紀錄,就可能刷新游標的記錄集。

#p#

7、 盡量使用索引

建立索引后,并不是每個查詢都會使用索引,在使用索引的情況下,索引的使用效率也會有很大的差別。只要我們在查詢語句中沒有強制指定索引,索引的選擇和使用方法是SQLSERVER的優化器自動作的選擇,而它選擇的根據是查詢語句的條件以及相關表的統計信息,這就要求我們在寫SQL語句的時候盡量使得優化器可以使用索引。

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

A、不要對索引字段進行運算,而要想辦法做變換,比如

  1. SELECT ID FROM T WHERE NUM/2=100 
  2.  
  3. 應改為: 
  4.  
  5. SELECT ID FROM T WHERE NUM=100*2 
  6.  
  7. SELECT ID FROM T WHERE NUM/2=NUM1 
  8.  
  9. 如果NUM有索引應改為: 
  10.  
  11. SELECT ID FROM T WHERE NUM=NUM1*2 
  12.  
  13. 如果NUM1有索引則不應該改。 
  14.  
  15. 發現過這樣的語句: 
  16.  
  17. SELECT 年,月,金額 FROM 結余表 
  18. WHERE 100*年+月=2007*100+10 
  19. 應該改為: 
  20.  
  21. SELECT 年,月,金額 FROM 結余表 
  22. WHERE 年=2007 AND 
  23.       月=10 

B、不要對索引字段進行格式轉換

日期字段的例子:

  1. WHERE CONVERT(VARCHAR(10), 日期字段,120)=’2008-08-15’ 
  2.  
  3. 應該改為 
  4.  
  5. WHERE日期字段〉=’2008-08-15’ AND 日期字段<’2008-08-16’ 
  6. ISNULL轉換的例子: 
  7. WHERE ISNULL(字段,’’)<>’’應改為:WHERE字段<>’’ 
  8. WHERE ISNULL(字段,’’)=’’不應修改 
  9. WHERE ISNULL(字段,’F’) =’T’應改為: WHERE字段=’T’ 
  10. WHERE ISNULL(字段,’F’)<>’T’不應修改 

C、 不要對索引字段使用函數

  1. WHERE LEFT(NAME, 3)='ABC' 或者WHERE SUBSTRING(NAME,1, 3)='ABC' 
  2.  
  3. 應改為: 
  4.  
  5. WHERE NAME LIKE 'ABC%' 

日期查詢的例子:

  1. WHERE DATEDIFF(DAY, 日期,'2005-11-30')=0應改為:WHERE 日期 >='2005-11-30' AND 日期 <'2005-12-1‘ 
  2. WHERE DATEDIFF(DAY, 日期,'2005-11-30')>0應改為:WHERE 日期 <'2005-11-30‘ 
  3. WHERE DATEDIFF(DAY, 日期,'2005-11-30')>=0應改為:WHERE 日期 <'2005-12-01‘ 
  4. WHERE DATEDIFF(DAY, 日期,'2005-11-30')<0應改為:WHERE 日期>='2005-12-01‘ 
  5. WHERE DATEDIFF(DAY, 日期,'2005-11-30')<=0應改為:WHERE 日期>='2005-11-30‘ 

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

比如:

  1. WHERE FAME+ ’.’+LNAME=‘HAIWEI.YANG’ 
  2.  
  3. 應改為: 
  4.  
  5. WHERE FNAME=‘HAIWEI’ AND LNAME=‘YANG’ 

8、 注意連接條件的寫法

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

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

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

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

9、其他需要注意的地方

經驗表明,問題發現的越早解決的成本越低,很多性能問題可以在編碼階段就發現,為了提早發現性能問題,需要注意:

A、程序員注意、關心各表的數據量。

B、編碼過程和單元測試過程盡量用數據量較大的數據庫測試,***能用實際數據測試。

C、每個SQL語句盡量簡單

D、不要頻繁更新有觸發器的表的數據

E、注意數據庫函數的限制以及其性能

10、學會分辯SQL語句的優劣

自己分辨SQL語句的優劣非常重要,只有自己能分辨優劣才能寫出高效的語句。

A、查看SQL語句的執行計劃,可以在查詢分析其使用CTRL+L圖形化的顯示執行計劃,一般應該注意百分比***的幾個圖形的屬性,把鼠標移動到其上面會顯示這個圖形的屬性,需要注意預計成本的數據,也要注意其標題,一般都是CLUSTERED INDEX SEEK 、INDEX SEEK 、CLUSTERED INDEX SCAN 、INDEX SCAN 、TABLE SCAN等,其中出現SCAN說明語句有優化的余地。也可以用語句

SET SHOWPLAN_ALL ON

要執行的語句

SET SHOWPLAN_ALL OFF

查看執行計劃的文本詳細信息。

B、用事件探查器跟蹤系統的運行,可疑跟蹤到執行的語句,以及所用的時間,CPU用量以及I/O數據,從而分析語句的效率。

C、可以用WINDOWS的系統性能檢測器,關注CPU、I/O參數

#p#

四、測試、試運行、維護階段

測試的主要任務是發現并修改系統的問題,其中性能問題也是一個重要的方面。重點應該放在發現有性能問題的地方,并進行必要的優化。主要進行語句優化、索引優化等。

試運行和維護階段是在實際的環境下運行系統,發現的問題范圍更廣,可能涉及操作系統、網絡以及多用戶并發環境出現的問題,其優化也擴展到操作系統、網絡以及數據庫物理存儲的優化。

這個階段的優花方法在這里不再展開,只說明下索引維護的方法:

A、可以用DBCC DBREINDEX語句或者SQL SERVER維護計劃設定定時進行索引重建,索引重建的目的是提高索引的效能。

B、可以用語句UPDATE STATISTICS或者SQL SERVER維護計劃設定定時進行索引統計信息的更新,其目的是使得統計信息更能反映實際情況,從而使得優化器選擇更合適的索引。

C、可以用DBCC CHECKDB或者DBCC CHECKTABLE語句檢查數據庫表和索引是否有問題,這兩個語句也能修復一般的問題。

五、網上資料中一些說法的個人不同意見

1、“應盡量避免在 WHERE 子句中對字段進行 NULL 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:

  1. SELECT ID FROM T WHERE NUM IS NULL 

可以在NUM上設置默認值0,確保表中NUM列沒有NULL值,然后這樣查詢:

  1. SELECT ID FROM T WHERE NUM=0” 

個人意見:經過測試,IS NULL也是可以用INDEX SEEK查找的,0和NULL是不同概念的,以上說法的兩個查詢的意義和記錄數是不同的。

2、“應盡量避免在 WHERE 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描。”

個人意見:經過測試,<>也是可以用INDEX SEEK查找的。

3、“應盡量避免在 WHERE 子句中使用 OR 來連接條件,否則將導致引擎放棄使用索引而進行全表掃描,如:

  1. SELECT ID FROM T WHERE NUM=10 OR NUM=20 

可以這樣查詢:

  1. SELECT ID FROM T WHERE NUM=10 
  2. UNION ALL 
  3. SELECT ID FROM T WHERE NUM=20” 

個人意見:主要對全表掃描的說法不贊同。

4、“IN 和 NOT IN 也要慎用,否則會導致全表掃描,如:

  1. SELECT ID FROM T WHERE NUM IN(1,2,3) 

對于連續的數值,能用 BETWEEN 就不要用 IN 了:

  1. SELECT ID FROM T WHERE NUM BETWEEN 1 AND 3” 

個人意見:主要對全表掃描的說法不贊同。

5、“如果在 WHERE 子句中使用參數,也會導致全表掃描。因為SQL只有在運行時才會解析局部變量,但優化程序不能將訪問計劃的選擇推遲到運行時;它必須在編譯時進行選擇。然 而,如果在編譯時建立訪問計劃,變量的值還是未知的,因而無法作為索引選擇的輸入項。如下面語句將進行全表掃描:

  1. SELECT ID FROM T WHERE NUM=@NUM 

可以改為強制查詢使用索引:

  1. SELECT ID FROM T WITH(INDEX(索引名)) WHERE NUM=@NUM” 

個人意見:關于局部變量的解釋比較奇怪,使用參數如果會影響性能,那存儲過程就該校除了,我堅持我上面對于強制索引的看法。

6、“盡可能的使用 VARCHAR/NVARCHAR 代替 CHAR/NCHAR ,因為首先變長字段存儲空間小,可以節省存儲空間,其次對于查詢來說,在一個相對較小的字段內搜索效率顯然要高些。”

個人意見:“在一個相對較小的字段內搜索效率顯然要高些”顯然是對的,但是字段的長短似乎不是由變不變長決定,而是業務本身決定。在 SQLSERVER6.5或者之前版本,不定長字符串字段的比較速度比定長的字符串字段的比較速度慢很多,所以對于那些版本,我們都是推薦使用定長字段存 儲一些關鍵字段。而在2000版本,修改了不定長字符串字段的比較方法,與定長字段的比較速度差別不大了,這樣為了方便,我們大量使用不定長字段?!?/p>

7、關于連接表的順序或者條件的順序的說法,經過測試,在SQL SERVER,這些順序都是不影響性能的,這些說法可能是對ORACLE有效。

 原文鏈接:http://www.cnblogs.com/tylerdonet/archive/2011/08/02/2125270.html

 

【編輯推薦】

  1. 淺述遠程Service Broker的實現
  2. Service Broker基礎應用(下)
  3. Service Broker基礎應用(上)
  4. 簡述Service Broker事件通知功能

 

 

責任編輯:艾婧 來源: Tyler‘s DotNet
相關推薦

2022-07-03 14:06:27

元宇宙交互技術AR

2018-01-09 16:56:32

數據庫OracleSQL優化

2021-07-16 23:01:03

SQL索引性能

2011-04-28 09:49:56

SQLwith子查詢

2018-04-19 09:02:14

SQL ServerSQL性能優化

2011-06-23 14:00:51

SQL點滴

2021-07-26 18:23:23

SQL策略優化

2011-05-11 09:49:32

線程等待SQL Server

2018-03-30 14:30:10

數據庫SQL語句性能優化

2018-03-30 13:59:22

數據庫SQL語句性能優化

2012-09-04 14:04:01

混合云混合云安全問題混合云安全

2011-04-21 10:06:40

SQL篩選

2011-09-13 10:25:05

數據庫點滴

2011-08-02 13:04:40

SQL Server

2011-09-09 10:10:13

SQL數據庫點滴

2012-08-16 12:50:29

2021-07-29 14:20:34

網絡優化移動互聯網數據存儲

2014-11-03 18:22:53

2021-07-01 07:34:09

LinuxIO模型

2022-02-16 14:10:51

服務器性能優化Linux
點贊
收藏

51CTO技術棧公眾號

国产一区二区不卡| 韩国一区二区三区视频| 久久久久久一级片| 国产精品入口尤物| 久久黄色免费网站| 一呦二呦三呦国产精品| 欧美乱熟臀69xxxxxx| 久久久久久久久久久综合| 亚洲av成人无码网天堂| 美女视频免费一区| 久久露脸国产精品| 久久久久99精品成人| 136福利精品导航| 在线观看视频一区| 日本香蕉视频在线观看| 都市激情在线视频| 粉嫩一区二区三区性色av| 国产999精品久久久| 欧美成人三级在线观看| 精品国产一区二区三区av片| 欧美哺乳videos| 天堂av在线网站| 97蜜桃久久| 最新国产成人在线观看| 欧美日本亚洲| 亚洲乱码国产乱码精品精软件| 久久影视一区| 日韩国产一区三区| 18深夜在线观看免费视频| 朝桐光一区二区| 午夜激情久久久| 可以免费看的黄色网址| 国产永久免费高清在线观看| 东方aⅴ免费观看久久av| 国产欧美精品在线播放| 中文字幕在线播| 亚洲人成高清| 欧美黑人巨大xxx极品| 亚洲国产精品一区二区久久hs| 精品国产乱码一区二区三区 | av在线不卡观看| 一级片在线免费播放| 亚洲三级电影在线观看| 久久精品国亚洲| 麻豆视频免费在线播放| 久久av中文| 亚洲精品资源美女情侣酒店| 中文字幕在线视频播放| 综合伊人久久| 欧美大片在线观看一区二区| 超碰91在线播放| 在线免费观看亚洲| 欧美久久久久中文字幕| 国产精品视频分类| 国产一区二区精品调教| 在线视频观看一区| 最近中文字幕一区二区| 99riav视频一区二区| 日本韩国欧美国产| 免费在线观看的毛片| 欧美男女交配| 欧美午夜精品久久久| 污片在线免费看| 久久99久久久精品欧美| 7878成人国产在线观看| 日韩av福利在线观看| 嫩呦国产一区二区三区av| 91麻豆精品久久久久蜜臀| 色婷婷激情视频| 日韩免费一级| 亚洲精品av在线播放| 精品黑人一区二区三区观看时间| 国产伦理久久久久久妇女 | 亚洲一区视频在线观看视频| 搞av.com| 中文字幕在线看片| 欧美亚洲精品一区| 91精产国品一二三产区别沈先生| 欧美亚洲黄色| 日韩欧美中文字幕一区| 妖精视频一区二区| 国产一区二区三区网| 色偷偷噜噜噜亚洲男人| 亚洲色图综合区| 亚洲美女少妇无套啪啪呻吟| 国产经典一区二区| 国产免费视频一区二区三区| 国产成人激情av| 欧美二级三级| 黄在线免费看| 午夜精品久久久久久久久| 精品免费国产一区二区| 亚洲男人在线| 亚洲精品国偷自产在线99热| 久久视频精品在线观看| 欧美体内she精视频在线观看| 久久久久中文字幕| 国产一区二区视频网站| 国产制服丝袜一区| 久久久水蜜桃| 国产精品久久麻豆| 婷婷综合另类小说色区| 一道本在线免费视频| 超碰成人福利| 上原亚衣av一区二区三区| 久久久精品视频在线| 日韩精品一二三四| 国产日韩精品久久| 美女羞羞视频在线观看| 大伊人狠狠躁夜夜躁av一区| 亚洲第一区第二区第三区| 亚洲va久久| 欧美日韩ab片| 中文字幕一区二区人妻| 99久久99久久免费精品蜜臀| 在线综合视频网站| 亚洲精品国产精品国自产观看| www.日本在线观看| 欧美高清在线视频| 国产乱子伦农村叉叉叉| 国产精品亚洲四区在线观看| 亚洲欧美日韩一区二区在线 | 欧美黄色三级网站| 中文字幕观看在线| wwwwww.欧美系列| 国产片侵犯亲女视频播放| 国产精品伦一区二区| 日韩精品中文字幕视频在线| 免费麻豆国产一区二区三区四区| 香蕉久久a毛片| 国产精品美女黄网| 国产福利视频在线观看| 欧美色成人综合| 亚洲永久精品ww.7491进入| 亚洲国产裸拍裸体视频在线观看乱了中文 | 欧洲大片精品免费永久看nba| 日韩久久精品一区| 久久99久久99精品免费看小说| 国产情侣一区| 官网99热精品| 欧洲中文在线| 日韩精品一区二区三区视频播放 | 亚洲产国偷v产偷v自拍涩爱| 最近中文字幕一区二区三区| 欧美成人乱码一二三四区免费| 亚洲三级网址| 日本一欧美一欧美一亚洲视频| 亚洲av无码片一区二区三区| 亚洲免费观看在线观看| 中文字幕第22页| 综合一区在线| 99电影在线观看| 日本色护士高潮视频在线观看| 欧美日韩不卡一区| 老司机深夜福利网站| 免费成人在线网站| 亚洲精品欧美精品| 色综合.com| 久久久精品2019中文字幕神马| 91激情在线观看| 1000部国产精品成人观看| 亚洲av无日韩毛片久久| 一本精品一区二区三区| 成人av播放| 草草在线视频| 亚洲无亚洲人成网站77777| 欧美性受xxx黑人xyx性爽| 中文字幕乱码久久午夜不卡 | 国产综合色视频| www.欧美黄色| 日韩极品在线| 国产精品日本精品| 国产淫片在线观看| 精品蜜桃在线看| www.国产一区二区| 国产精品网曝门| 国产精品91av| 另类av一区二区| 伊人久久大香线蕉av一区| 日韩第一区第二区| 2018国产精品视频| 91伦理视频在线观看| 91精品国产免费| 免费在线观看黄网站| 日本一二三四高清不卡| 丰满少妇一区二区三区专区| 国产精品色网| 偷拍盗摄高潮叫床对白清晰| 6080成人| 国产精品色午夜在线观看| 尤物视频在线看| 亚洲免费av电影| 国产三级按摩推拿按摩| 大桥未久av一区二区三区| 99自拍视频在线| 972aa.com艺术欧美| 色一情一区二区| 国产精品乱看| 精品一区二区三区毛片| 日韩激情网站| 成人免费91在线看| av在线不卡精品| 国内外成人免费激情在线视频| 日韩精品视频无播放器在线看| 欧美色图在线观看| 日韩免费在线视频观看| 日韩美女视频19| 乐播av一区二区三区| 国产99精品国产| 亚洲成人福利在线| 免费欧美在线| 欧美做暖暖视频| 日韩精品2区| 老司机精品福利在线观看| 亚洲成人五区| 91免费国产网站| 成人高清一区| 欧美一区二三区| 黄色的视频在线观看| zzjj国产精品一区二区| 成人好色电影| 亚洲天堂成人在线视频| 天堂网2014av| 精品国产免费人成在线观看| 国产日韩在线观看一区| 欧美三级中文字| 久久亚洲精品石原莉奈| 精品福利视频导航| 久久久久久久久99| 一区二区在线看| 精品国产视频在线观看| 中文字幕高清不卡| 一级黄色片网址| 久久精品欧美一区二区三区麻豆 | 久久综合久久久久88| 久久人妻少妇嫩草av蜜桃| 国产乱子轮精品视频| av中文字幕网址| 久久99这里只有精品| 黄色免费网址大全| 日韩激情av在线| 日韩欧美在线免费观看视频| 99riav1国产精品视频| 久草视频国产在线| 妖精视频成人观看www| 成人免费观看cn| 99成人在线| 99精品人妻少妇一区二区 | 欧美激情区在线播放| caoporn免费在线视频| 美女福利视频一区| 婷婷色在线资源| 久久久久久69| 888av在线视频| 4444欧美成人kkkk| 神马久久资源| 国产玖玖精品视频| 国产精品日本一区二区不卡视频| 国产精品视频在线播放| 欧美韩国日本| 99re视频在线播放| 91午夜精品| 久久香蕉综合色| 欧美日韩一区二区三区视频播放| 欧美日韩国产高清视频| 欧美色图国产精品| 精品一区二区成人免费视频| 欧美永久精品| 黄色国产一级视频| 久久精选视频| 岛国av免费在线| 国产成人精品影院| 7788色淫网站小说| 国产欧美日产一区| 放荡的美妇在线播放| 亚洲成av人片一区二区梦乃| 国产精品视频久久久久久久| 在线观看网站黄不卡| av在线亚洲天堂| 日韩电影中文字幕在线观看| 国产片在线观看| 欧美精品手机在线| 一区二区精品伦理...| 国产裸体写真av一区二区 | 高潮在线视频| 国产精品视频资源| 2021年精品国产福利在线| 欧美激情第六页| 亚洲欧洲日韩| 国内外成人免费激情视频| 国产做a爰片久久毛片| 成人午夜精品无码区| 国产欧美日韩视频在线观看| 国产精品 欧美激情| 欧美日韩精品国产| 国产三级漂亮女教师| 日韩高清av一区二区三区| 色的视频在线免费看| 欧美在线观看一区二区三区| 57pao成人永久免费| 久久久亚洲综合网站| 久久久久国产| 国产一级不卡毛片| 丁香婷婷综合色啪| 国产在线免费看| 91极品美女在线| 理论片中文字幕| 日韩综合视频在线观看| 伊人网在线播放| 国产成人免费观看| 图片区亚洲欧美小说区| 日本熟妇人妻xxxxx| 成人永久免费视频| 四虎永久免费在线| 在线观看国产一区二区| 头脑特工队2免费完整版在线观看| 综合网中文字幕| 欧美成人性网| 久久久久久艹| 亚洲大黄网站| 亚洲成人精品在线播放| 一区二区中文视频| 老熟妇一区二区三区啪啪| 日韩精品一二三四区| 都市激情久久综合| 91亚洲永久免费精品| 日韩av在线播放网址| 免费在线观看日韩视频| 成人av在线电影| 久久精品一级片| 日韩欧美一区在线| 最新日本在线观看| 97netav| 永久91嫩草亚洲精品人人| 国产视频1区2区3区| 国产精品人妖ts系列视频| 天堂网免费视频| 亚洲欧洲日产国码av系列天堂| 久久免费电影| 国产伦精品一区| 亚洲国产一区二区三区a毛片| 欧美一级xxxx| 国产精品久久久久久久久免费樱桃| 西西44rtwww国产精品| 亚洲成人黄色在线| 成人在线高清免费| 国产欧美日韩综合精品二区| 精品999网站| 亚洲熟女一区二区| 欧美性猛交xxxx| 青青草在线视频免费观看| 欧洲精品久久久| 精品免费在线| www.99r| 一区二区三区四区蜜桃| 亚洲精品人妻无码| 97久久超碰福利国产精品…| 欧美激情极品| 999精品网站| 中文字幕 久热精品 视频在线 | 视频在线观看91| 东方伊人免费在线观看| 欧美色图12p| 超碰在线观看免费| 国产伦精品一区二区三区视频孕妇 | 真实国产乱子伦精品一区二区三区| 成年人网站大全| 国产精品三级久久久久三级| 在线观看国产精品视频| 久久天天躁狠狠躁夜夜爽蜜月| 91成人短视频在线观看| 高清无码一区二区在线观看吞精| 高清国产一区二区| 国产精品蜜臀| 日韩经典中文字幕| 亚洲美女久久精品| 色播亚洲婷婷| 久久99久久久欧美国产| 精品人妻伦九区久久aaa片| 欧美mv日韩mv| 欧美动物xxx| 欧美视频第二页| av在线免费播放网站| 亚洲最大成人在线| 国产欧美综合视频| 欧美一区二区性放荡片| 国产在线拍揄自揄拍视频| 美女精品国产| 国模无码大尺度一区二区三区| 91狠狠综合久久久久久| 欧美一级免费大片| 在线观看欧美日韩电影| 精品一区二区成人免费视频| 白白色亚洲国产精品| 中文字幕欧美人妻精品一区蜜臀 | 98精品在线视频| 成人久久久久| 天天躁日日躁狠狠躁免费麻豆| 日韩人体视频一二区| av超碰免费在线|