程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> SqlServer數據庫 >> 關於SqlServer >> 數據庫優化實踐

數據庫優化實踐

編輯:關於SqlServer

       優化技巧主要是面向DBA的,但我認為即使是開發人員也應該掌握這些技巧,因為不是每個開發團隊都配有專門的DBA的。

      第九步:合理組織數據庫文件組和文件

      創建SQL Server數據庫時,數據庫服務器會自動在文件系統上創建一系列的文件,之後創建的每一個數據庫對象實際上都是存儲在這些文件中的。SQL Server有下面三種文件:

      1).mdf文件

      這是最主要的數據文件,每個數據庫只能有一個主數據文件,所有系統對象都存儲在主數據文件中,如果不創建次要數據文件,所有用戶對象(用戶創建的數據庫對象)也都存儲在主數據文件中。

      2).ndf文件

      這些都是次要數據文件,它們是可選的,它們存儲的都是用戶創建的對象。

      3).ldf文件

      這些是事務日志文件,數量從一到幾個不等,它裡面存儲的是事務日志。

      默認情況下,創建SQL Server數據庫時會自動創建主數據文件和事務日志文件,當然也可以修改這兩個文件的屬性,如保存路徑。

      文件組

      為了便於管理和獲得更好的性能,數據文件通常都進行了合理的分組,創建一個新的SQL Server數據庫時,會自動創建主文件組,主數據文件就包含在主文件組中,主文件組也被設為默認組,因此所有新創建的用戶對象都自動存儲在主文件組中(具體說就是存儲在主數據文件中)。

      如果你想將你的用戶對象(表、視圖、存儲過程和函數等)存儲在次要數據文件中,那需要:

      1)創建一個新的文件組,並將其設為默認文件組;

      2)創建一個新的數據文件(.ndf),將其歸於第一步創建的新文件組中。

      以後創建的對象就會全部存儲在次要文件組中了。

      注意:事務日志文件不屬於任何文件組。

      文件/文件組組織最佳實踐

      如果你的數據庫不大,那麼默認的文件/文件組應該就能滿足你的需要,但如果你的數據庫變得很大時(假設有1000MB),你可以(應該)對文件/文件組進行調整以獲得更好的性能,調整文件/文件組的最佳實踐內容如下:

      1)主文件組必須完全獨立,它裡面應該只存儲系統對象,所有的用戶對象都不應該放在主文件組中。主文件組也不應該設為默認組,將系統對象和用戶對象分開可以獲得更好的性能;

      2)如果有多塊硬盤,可以將每個文件組中的每個文件分配到每塊硬盤上,這樣可以實現分布式磁盤I/O,大大提高數據讀寫速度;

      3)將訪問頻繁的表及其索引放到一個單獨的文件組中,這樣讀取表數據和索引都會更快;

      4)將訪問頻繁的包含Text和Image數據類型的列的表放到一個單獨的文件組中,最好將其中的Text和Image列數據放在一個獨立的硬盤中,這樣檢索該表的非Text和Image列時速度就不會受Text和Image列的影響;

      5)將事務日志文件放在一個獨立的硬盤上,千萬不要和數據文件共用一塊硬盤,日志操作屬於寫密集型操作,因此保證日志寫入具有良好的I/O性能非常重要;

      6)將“只讀”表單獨放到一個獨立的文件組中,同樣,將“只寫”表單獨放到一個文件組中,這樣只讀表的檢索速度會更快,只寫表的更新速度也會更快;

      7)不要過度使用SQL Server的“自動增長”特性,因為自動增長的成本其實是很高的,設置“自動增長”值為一個合適的值,如一周,同樣,也不要過度頻繁地使用“自動收縮”特性,最好禁用掉自動收縮,改為手工收縮數據庫大小,或使用調度操作,設置一個合理的時間間隔,如一個月。

      第十步:在大表上應用分區

      什麼是表分區?

      表分區就是將大表拆分成多個小表,以免檢索數據時掃描的數據太多,這個思想參考了“分而治之”的理論。

      當你的數據庫中有一個大表(假設有上百萬行記錄),如果其它優化技巧都用上了,但查詢速度仍然非常慢時,你就應該考慮對這個表進行分區了。首先來看一下分區的類型:

      水平分區:假設有一個表包括千萬行記錄,為了便於理解,假設表有一個自動增長的主鍵字段(如id),我們可以將表拆分成10個獨立的分區表,每個分區包含100萬行記錄,分區就要依據id字段的值實施,即第一個分區包含id值從1-1000000的記錄,第二個分區包含1000001-2000000的記錄,以此類推。這種以水平方向分割表的方式就叫做水平分區。

      垂直分區:假設有一個表的列數和行數都非常多,其中某些列被經常訪問,其余的列不是經常訪問。由於表非常大,所有檢索操作都很慢,因此需要基於頻繁訪問的列進行分區,這樣我們可以將這個大表拆分成多個小表,每個小表由大表的一部分列組成,這種垂直拆分表的方法就叫做垂直分區。

      另一個垂直分區的原則是按有索引的列無索引列進行拆分,但這種分區法需要小心,因為如果任何查詢都涉及到檢索這兩個分區,SQL引擎不得不連接這兩個分區,那樣的話性能反而會低。

      本文主要對水平分區做一介紹。

      分區最佳實踐

      1)將大表分區後,將每個分區放在一個獨立的文件中,並將這個文件存放在獨立的硬盤上,這樣數據庫引擎可以同時並行檢索多塊硬盤上的不同數據文件,提高並發讀寫速度;

      2)對於歷史數據,可以考慮基於歷史數據的“年齡”進行分區,例如,假設表中存儲的是訂單數據,可以使用訂單日期列作為分區的依據,如將每年的訂單數據做成一個分區。

      如何分區?

      假設Order表中包含了四年(1999-2002)的訂單數據,有上百萬的記錄,那如果要對這個表進行分區,采取的步驟如下:

      1)添加文件組

      使用下面的命令創建一個文件組:

      ALTER DATABASE OrderDB ADD FILEGROUP [1999]

      ALTER DATABASE OrderDB ADD FILE (NAME = N'1999', FILENAME

      = N'C:OrderDB1999.ndf', SIZE = 5MB, MAXSIZE = 100MB, FILEGROWTH = 5MB) TO

      FILEGROUP [1999]

      通過上面的語句我們添加了一個文件組1999,然後增加了一個次要數據文件“C:OrderDB1999.ndf”到這個文件組中。

      使用上面的命令再創建三個文件組2000,2001和2002,每個文件組存儲一年的銷售數據。

      2)創建分區函數

      分區函數是定義分界點的一個對象,使用下面的命令創建分區函數:

      CREATE PARTITION FUNCTION FNOrderDateRange (DateTime) AS

      RANGE LEFT FOR VALUES ('19991231', '20001231', '20011231')

      上面的分區函數指定:

      DateTime<=1999/12/31的記錄進入第一個分區;

      DateTime > 1999/12/31 且 <= 2000/12/31的記錄進入第二個分區;

      DateTime > 2000/12/31 且 <= 2001/12/31的記錄進入第三個分區;

      DateTime > 2001/12/31的記錄進入第四個分區。

      RANGE LEFT指定應該進入左邊分區的邊界值,例如小於或等於1999/12/31的值都應該進入第一個分區,下一個值就應該進入第二個分區了。如果使用RANGE RIGHT,邊界值以及大於邊界值的值都應該進入右邊的分區,因此在這個例子中,邊界值2000/12/31就應該進入第二個分區,小於這個邊界值的值就應該進入第一個分區。

      3)創建分區方案

      通過分區方案在表/索引的分區和存儲它們的文件組之間建立映射關系。創建分區方案的命令如下:

      CREATE PARTITION SCHEME OrderDatePScheme AS PARTITION FNOrderDateRange

      TO ([1999], [2000], [2001], [2002])

      在上面的命令中,我們指定了:

      第一個分區應該進入1999文件組;

      第二個分區就進入2000文件組;

      第三個分區進入2001文件組;

      第四個分區進入2002文件組。

      4)在表上應用分區

      至此,我們定義了必要的分區原則,現在需要做的就是給表分區了。首先使用DROP INDEX命令刪除表上現有的聚集索引,通常主鍵上有聚集索引,如果是刪除主鍵上的索引,還可以通過DROP CONSTRAINT刪除主鍵來間接刪除主鍵上的索引,如下面的命令刪除PK_Orders主鍵:

      ALTER TABLE Orders DROP CONSTRAINT PK_Orders;

      在分區方案上重新創建聚集索引,命令如下:

      CREATE UNIQUE CLUSTERED INDEX PK_Orders ON Orders(OrderDate) ON

      OrderDatePScheme (OrderDate)

      假設OrderDate列的數據在表中是唯一的,表將基於分區方案OrderDatePScheme被分區,最終被分成四個小的部分,存放在四個文件組中。如果你對如何分區還有不清楚的地方,建議你去看看微軟的官方文章“SQL Server 2005中的分區表和索引”(地址:http://msdn.microsoft.com/en-us/library/ms345146%28SQL.90%29.aspx)。

      第十一步:使用TSQL模板更好地管理DBMS對象(額外的一步)

      為了更好地管理DBMS對象(存儲過程,函數,視圖,觸發器等),需要遵循一致的結構,但由於某些原因(主要是時間限制),我們未能維護一個一致的結構,因此後來遇到性能問題或其它原因需要重新調試這些代碼時,那感覺就像是做噩夢。

      為了幫助大家更好地管理DBMS對象,我創建了一些TSQL模板,利用這些模板你可以快速地開發出結構一致的DBMS對象。

      如果你的團隊有人專門負責檢查團隊成員編寫的TSQL代碼,在這些模板中專門有一個“審查”段落用來描寫審查意見。

      我提交幾個常見的DBMS對象模板,它們是:

      Template_StoredProcedure.txt:存儲過程模板(http://www.codeproject.com/KB/database/OrganizeFilesAndPartition/Template_StoredProcedure.txt)

      Template_View.txt:視圖模板(http://www.codeproject.com/KB/database/OrganizeFilesAndPartition/Template_Trigger.txt)

      Template_Trigger.txt:觸發器模板(http://www.codeproject.com/KB/database/OrganizeFilesAndPartition/Template_ScalarFunction.txt)

      Template_ScalarFunction.txt:標量函數模板(http://www.codeproject.com/KB/database/OrganizeFilesAndPartition/Template_TableValuedFunction.txt)

      emplate_TableValuedFunction.txt:表值函數模板(http://www.codeproject.com/KB/database/OrganizeFilesAndPartition/Template_View.txt)

      1)如何創建模板?

      首先下載前面給出的模板代碼,然打開SQL Server管理控制台,點擊“查看”*“模板浏覽器”;

      點擊“存儲過程”節點,點擊右鍵,在彈出的菜單中選擇“新建”*“模板”,為模板取一個易懂的名字;

      在新創建的模板上點擊右鍵,選擇“編輯”,在彈出的窗口中輸入身份驗證信息,點擊“連接”;

      連接成功後,在編輯器中打開下載的Template_StoredProcedure.txt,拷貝文件中的內容粘貼到新建的模板中,然後點擊“保存”。

      上面是創建一個存儲過程模板的過程,創建其它DBMS對象過程類似。

      2)如何使用模板?

      創建好模板後,下面就演示如何使用模板了。

      首先在模板浏覽器中,雙擊剛剛創建的存儲過程模板,彈出身份驗證對話框,輸入對應的身份信息,點擊“連接”;

      連接成功後,模板將會在編輯器中打開,變量將會賦上適當的值;

      按Ctrl+Shift+M為模板指定值,如下圖所示;

    數據庫優化實踐   三聯

      圖 1 為模板參數指定值

      點擊“OK”,然後在SQL Server管理控制台中選擇目標數據庫,然後點擊“執行”按鈕;

      如果一切順利,存儲過程就創建成功了。你可以根據上面的步驟創建其它DBMS對象。

      小結

      優化講究的是一種“心態”,在優化數據庫性能時,首先要相信性能問題總是可以解決的,然後就是結合經驗和最佳實踐努力進行優化,最重要的是要盡量預防性能問題的發生,在開發和部署期間,要利用一切可利用的技術和經驗進行提前評估,千萬不要等問題出現了才去想辦法解決,在開發期間多花一個小時實施最佳實踐,最後可能會給你節約上百小時的故障診斷和排除時間,要學會聰明地工作,而不是辛苦地工作!

    1. 上一頁:
    2. 下一頁:
    Copyright © 程式師世界 All Rights Reserved