1. 程式人生 > >SQL優化-索引 (二)結合實際,談索引使用的誤區

SQL優化-索引 (二)結合實際,談索引使用的誤區

(三)結合實際,談索引使用的誤區

  理論的目的是應用。雖然我們剛才列出了何時應使用聚集索引或非聚集索引,但在實踐中以上規則卻很容易被忽視或不能根據實際情況進行綜合分析。下面我們將根據在實踐中遇到的實際問題來談一下索引使用的誤區,以便於大家掌握索引建立的方法。

  1、主鍵就是聚集索引

  這種想法筆者認為是極端錯誤的,是對聚集索引的一種浪費。雖然SQL SERVER預設是在主鍵上建立聚集索引的。

  通常,我們會在每個表中都建立一個ID列,以區分每條資料,並且這個ID列是自動增大的,步長一般為1。我們的這個辦公自動化的例項中的列Gid就是如此。此時,如果我們將這個列設為主鍵,SQL SERVER會將此列預設為聚集索引。這樣做有好處,就是可以讓您的資料在資料庫中按照ID進行物理排序,但筆者認為這樣做意義不大。

  顯而易見,聚集索引的優勢是很明顯的,而每個表中只能有一個聚集索引的規則,這使得聚集索引變得更加珍貴。

  從我們前面談到的聚集索引的定義我們可以看出,使用聚集索引的最大好處就是能夠根據查詢要求,迅速縮小查詢範圍,避免全表掃描。在實際應用中,因為ID號是自動生成的,我們並不知道每條記錄的ID號,所以我們很難在實踐中用ID號來進行查詢。這就使讓ID號這個主鍵作為聚集索引成為一種資源浪費。其次,讓每個ID號都不同的欄位作為聚集索引也不符合“大數目的不同值情況下不應建立聚合索引”規則;當然,這種情況只是針對使用者經常修改記錄內容,特別是索引項的時候會負作用,但對於查詢速度並沒有影響。

  在辦公自動化系統中,無論是系統首頁顯示的需要使用者簽收的檔案、會議還是使用者進行檔案查詢等任何情況下進行資料查詢都離不開欄位的是“日期”還有使用者本身的“使用者名稱”。

  通常,辦公自動化的首頁會顯示每個使用者尚未簽收的檔案或會議。雖然我們的where語句可以僅僅限制當前使用者尚未簽收的情況,但如果您的系統已建立了很長時間,並且資料量很大,那麼,每次每個使用者開啟首頁的時候都進行一次全表掃描,這樣做意義是不大的,絕大多數的使用者1個月前的檔案都已經瀏覽過了,這樣做只能徒增資料庫的開銷而已。事實上,我們完全可以讓使用者開啟系統首頁時,資料庫僅僅查詢這個使用者近3個月來未閱覽的檔案,通過“日期”這個欄位來限制表掃描,提高查詢速度。如果您的辦公自動化系統已經建立的2年,那麼您的首頁顯示速度理論上將是原來速度8倍,甚至更快。

  在這裡之所以提到“理論上”三字,是因為如果您的聚集索引還是盲目地建在ID這個主鍵上時,您的查詢速度是沒有這麼高的,即使您在“日期”這個欄位上建立的索引(非聚合索引)。下面我們就來看一下在1000萬條資料量的情況下各種查詢的速度表現(3個月內的資料為25萬條):

  (1)僅在主鍵上建立聚集索引,並且不劃分時間段:

  Select gid,fariqi,neibuyonghu,title from tgongwen

  用時:128470毫秒(即:128秒)

  (2)在主鍵上建立聚集索引,在fariq上建立非聚集索引:

  select gid,fariqi,neibuyonghu,title from Tgongwen

  where fariqi> dateadd(day,-90,getdate())

  用時:53763毫秒(54秒)

  (3)將聚合索引建立在日期列(fariqi)上:

  select gid,fariqi,neibuyonghu,title from Tgongwen

  where fariqi> dateadd(day,-90,getdate())

  用時:2423毫秒(2秒)

  雖然每條語句提取出來的都是25萬條資料,各種情況的差異卻是巨大的,特別是將聚集索引建立在日期列時的差異。事實上,如果您的資料庫真的有1000萬容量的話,把主鍵建立在ID列上,就像以上的第1、2種情況,在網頁上的表現就是超時,根本就無法顯示。這也是我摒棄ID列作為聚集索引的一個最重要的因素。

  得出以上速度的方法是:在各個select語句前加:

  declare @d datetime

  set @d=getdate()

  並在select語句後加:

  select [語句執行花費時間(毫秒)]=datediff(ms,@d,getdate())