我們做開發的人員,雖說自己不是專業從事數據庫方面研究的(如DBA),但很多時候,公司沒有專門的DBA,所以拿到具體的項目中,整體的數據庫設計都是開發人員自己寫的,隨着時間的推移,加上開發經驗的增長,越來越關心如何設計好的數據庫,如何寫出高效的sql語句。之所以非常關心數據庫及sql語句的寫法,主要是在程序邏輯代碼上大家都有可能寫出一樣的效率的功能方法來,而sql語句呢,對於同樣的結果集,一個初級的開發人員與一個資深的開發人員或者DBA寫出的sql語句執行效率有着很大的差距。這里對數據庫設計略過,主要說說正確建立索引,帶來的性能提高。(還好,我們公司有DBA,自己寫好的sql語句可以讓他幫忙看看)
看sql 的性能,主要看執行計划,還有cpu成本,io成本等。這里就以一個簡的表為例。
首先,創建一個簡單的表,一般會先建個主鍵,系統自動以主鍵建聚集索引。語句如下:
Code 1CREATE TABLE [dbo].[Article]( 2 [Id] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL, 3 [MsId] [int] NOT NULL, 4 [Title] [nvarchar](96) NOT NULL, 5 [TitleBak] [nvarchar](96) NOT NULL, 6 [Summary] [nvarchar](512) NOT NULL, 7 [SummaryImageUrl] [nvarchar](256) NOT NULL, 8 [Tag] [nvarchar](50) NOT NULL, 9 [ArticleChannel_Id] [int] NOT NULL, 10 [ArticleCategory_Id] [int] NOT NULL, 11 [IsApproved] [bit] NOT NULL, 12 [Creator_Id] [int] NOT NULL, 13 [CreatedDateTime] [datetime] NOT NULL, 14 [ModifiedDateTime] [datetime] NOT NULL, 15 [ViewCount] [int] NOT NULL, 16 [ReplyCount] [int] NOT NULL, 17 [DiggCount] [int] NOT NULL, 18 [FavoriteCount] [int] NOT NULL, 19 [LastReplyUser_Id] [int] NOT NULL, 20 [LastReplyDateTime] [datetime] NOT NULL, 21 [RightType] [int] NOT NULL, 22 [IsDisplayContent] [bit] NOT NULL, 23 [IsSensitive] [bit] NOT NULL, 24 [Source] [int] NOT NULL, 25 CONSTRAINT [PK_Articles] PRIMARY KEY CLUSTERED 26( 27 [Id] ASC 28)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 29) ON [PRIMARY] 30
填充200000測試數據,
Code 1DECLARE @number INT 2SET @number = 200000 3 4WHILE @number > 0 5BEGIN 6 INSERT dbo.Article 7 ( 8 MsId, 9 Title, 10 TitleBak, 11 Summary, 12 SummaryImageUrl, 13 14 Tag, 15 ArticleChannel_Id, 16 ArticleCategory_Id, 17 IsApproved, 18 Creator_Id, 19 20 CreatedDateTime, 21 ModifiedDateTime, 22 ViewCount, 23 ReplyCount, 24 DiggCount, 25 26 FavoriteCount, 27 LastReplyUser_Id, 28 LastReplyDateTime, 29 RightType, 30 IsDisplayContent, 31 32 IsSensitive, 33 Source 34 ) 35 VALUES 36 ( 37 @number, 38 'Title'+cast(@number AS VARCHAR(20)), 39 'TitleBak'+cast(@number AS VARCHAR(20)), 40 'Summary'+cast(@number AS VARCHAR(20)), 41 'SummaryImageUrl'+cast(@number AS VARCHAR(20)), 42 43 'Tag'+cast(@number AS VARCHAR(20)), 44 1, 45 2, 46 0, 47 @number, 48 49 GETDATE(), 50 GETDATE(), 51 100, 52 29, 53 123, 54 55 12, 56 @number, 57 GETDATE(), 58 1, 59 0, 60 61 0, 62 2 63 64 ) 65 SET @number=@number-1 66END 67
創建索引,什么時候創建,為哪個字段創建等等一系列的問題在這里統統的撂下,在這里進行一步步的帶有試探的創建非聚集索引,看看建立索引前后以及不同的索引會有什么樣的不同。
先說明一下,通過執行計划,判斷是否需要優化sql的一個簡單規則是:看執行計划中的操作是seek(搜索)還是scan(掃描)
長話短說,馬上開始,
WITH TEMP AS ( SELECT ROW_NUMBER() OVER (ORDER BY CreatedDateTime) AS ROW,CreatedDateTime,ViewCount FROM Article WHERE Creator_Id=199996 ) SELECT * FROM TEMP WHERE ROW BETWEEN 1 AND 5
通過執行計划,看到是操作是聚集索引掃描。我們剛才說了,seek操作性能更好一些,那如何優化這條語句呢,對Creator_Id建非聚集索引。
創建Ix_article_creatorid 索引,
CREATE INDEX Ix_article_creatorid ON Article(Creator_Id)
再看下執行計划,
哦,加了Ix_article_creatorid索引后,聚集索引掃描操作改為索引查找和聚集索引查找,對於我們開發人員來說,一般的認為可以了。如果所開發的系統在正常運行一段時間后,需要優化,可以對此語句繼續進行優化。
看完執行計划,想到了應該再看看cpu占用時間,IO資源等情況,主要用到命令
set statistics io 和 set statistics,這是性能調優時查看相關cpu占用時間,IO資源數據的兩個比較重要的命令。
今天就先到了,下篇再介紹這兩個命令吧。
備注:
其實沒有詳細介紹如何創建高效性能的索引,主要原因是根據不同的環境對待系統的要求不同,而優化也有所不同,當一個系統查詢比較頻繁,而新建,修改等操作比較少時,可以創建覆蓋索引,將查詢字段和where子句里的字段全部包含在內,這樣查詢的速度會比以前快很多,同時也帶來弊端,就是新建或修改等操作時,比沒有索引或沒有建立覆蓋索引時的要慢。總結一句話就是,具體問題具體分析。
數據庫里的知識也是博大精深,並不是當初認為會寫幾條sq l語句就以為非常精通了數據庫什么的,真正要寫出好的語句,得下功夫,了解數據庫的底層,再經常問問DB牛人,慢慢積累后,也許你也能成為DB牛人呢。總結一句話就是,只要功夫深,鐵杵磨成針。