2011-02-15 102 views
0

我有了在存儲過程下面的SQL查詢的ASP.NET應用程序:的SQL Server存儲過程的性能

SELECT @result = COUNT(id) 
FROM course_tracking 
WHERE employee_number = @employee_number 
AND course_code = @course_code 

IF @result = 0 
BEGIN 
    INSERT INTO COURSE TRACKING 
END 
ELSE 
    UPDATE COURSE TRACKING 

Course Tracking表中有將近一百萬行和SQL事件探查器顯示40K之間每執行一次這個過程幾秒鐘就讀取50k。

因爲我不是一個SQL Server性能測試的傢伙...什麼是最好的方法來糾正?

任何幫助,非常感謝。

感謝

+1

確保`course_code`和`employee_number`都編入索引。覆蓋指數應該可以正常工作。 – JNK 2011-02-15 20:28:07

+3

什麼是SQL Server版本?因爲SQLServer 2008爲你提供了`MERGE`能力,這對於這樣的upserts來說非常棒。 – Matthew 2011-02-15 20:30:16

+0

@JNK,他不需要包括計數的id列嗎? – DForck42 2011-02-15 20:37:31

回答

1

亞歷克斯,

可以有許多原因的大量閱讀,而且我相信,@喬納森的回答將幫助,或者掩蓋了問題,現在。獲得大量讀取的原因將是因爲您缺少一些關鍵索引,並且/或者您的表統計信息不是最新的,或者它已關閉。

現在在像這樣的大表上進行性能調整可能會很複雜,如果它被許多其他過程,視圖和查詢使用。因爲更改任何索引都會對現在正在運行良好的其他查詢產生巨大影響,但是如果表缺少任何索引,則任何更改都可能會有所幫助。需要考慮的事情,當你試圖優化這樣的事情是:

  1. 如何經常是這樣的查詢運行
  2. 當它運行的它的系統
  3. 什麼是這個最頻繁的操作 上影響其他進程表,插入或更新?

如果這個查詢每天運行一次,或者很少發生,並且不影響其他進程,我可能會傾向於離開它。但是,如果這是一個運行頻繁和/或影響其他進程的進程,那麼您需要修復它。現在通過修復它,它可以很簡單,只要添加WITH(NOLOCK)表提示,如果您發現它阻塞,但如果它運行頻繁,然後查看索引和統計信息。

如果你在這個表上有很多插入,那麼任何額外的索引都會影響插入性能,但它會加速更新。然後是索引填充因子等等。我的觀點是,在Sql框中進行性能調整非常複雜,並且大部分時間都需要整個圖片。

所以我建議你在這裏提一些提示,因爲沒有人知道你的系統和你一樣,你可以做出一些決定,並做實驗,並從中學習!啓用您的查詢執行計劃並查看它,看看是否有任何表掃描,它們不好,並且表明缺少適當的索引,關鍵查找也是如此。

但看着你在這裏給出的查詢,並忽略了其他因素,這裏是我的建議。

確保索引中包含employee_numbercourse_code的非聚簇索引。如果是Sql 2008,你可以添加一些包含的列,如果你有其他查詢過濾這兩列,但輸出其他列。至於它們應該在指數中上升還是下降取決於你,但將它們都作爲升序留下。

然後在查詢,使用什麼@Jonathan提出,對於小的修改(+1你!),在表中添加WITH(NOLOCK)提示。這會告訴Sql優化器在讀取表時不要鎖定表,但是您將能夠讀取髒數據。通常不是問題,除非它是一個高度事務性的表,大量的更新和插入一直在進行。

IF EXISTS(SELECT 1 FROM course_tracking WITH(NOLOCK) 
WHERE employee_number = @employee_number 
     AND course_code = @course_code) 
BEGIN 
    UPDATE COURSE TRACKING 
END 
ELSE 
BEGIN 
    INSERT INTO COURSE TRACKING 
END 

此外,檢查,如果你統計的數據庫自動更新如果沒有,創建維護作業,將一天一次更新,當服務器是最不活躍。以此爲查詢EXEC sp_MSForEachTable 'UPDATE STATISTICS ? WITH FULLSCAN'

4

試試這個

IF EXISTS(SELECT 1 FROM course_tracking 
WHERE employee_number = @employee_number 
AND course_code = @course_code) 
BEGIN 
    UPDATE COURSE TRACKING 
END 
ELSE 
BEGIN 
    INSERT INTO COURSE TRACKING 
END 
0

如果你有SQL 2008年,MERGE語法是好的。皮納爾戴夫具有良好的演練http://blog.sqlauthority.com/2008/08/28/sql-server-2008-introduction-to-merge-statement-one-statement-for-insert-update-delete/

MERGE course_tracking AS c 
ON c.employee_number = @employee_number 
AND c.course_code = @course_code 
WHEN MATCHED THEN 
UPDATE STUFF 
WHEN NOT MATCHED THEN 
INSERT STUFF 
GO 
+0

語法都很好,但沒有合適的索引和糟糕的表格設計,這隻會掩蓋問題,如果它會掩蓋它。 – Ryk 2011-02-15 21:58:15

1

創建一個SQL代理作業如果查詢實際更新的行WHERE employee_number = @employee_number AND course_code = @course_code),那麼你可以試試這種方法:

UPDATE course_tracking 
SET ... 
WHERE employee_number = @employee_number 
    AND course_code = @course_code; 
IF @@ROWCOUNT = 0 
    INSERT INTO course_tracking 
    ...