在創建復合索引時,除了考慮索引鍵的選取外,還需考慮索引鍵的先后順序。下面借助一些場景來講解。
場景1表dbo.UserLoginStats記錄每個用戶每天的登錄統計,目前表中存放10億數據,每天新增數據500W(每天每個用戶很少幾條條記錄),目前系統有用戶8000W,有查詢:SELECT * FROM dbo.UserLoginStatsWHERE UserID=@userIDAND LoginDay=@loginDay
對于此查詢,可以創建索引:
CREATE INDEX IX_UserID_LoginDay ON dbo.UserLoginStats(UserID,LoginDay)或CREATE INDEX IX_LoginDay_UserID ON dbo.UserLoginStats(LoginDay,UserID)
以上兩種索引都可以幫助查詢快速返回結果,并且消耗的IO相同,消耗的CPU時間也大致相同,因此對于該查詢來說,兩個索引沒有區別,但我們該使用哪一個查詢呢?
假設索引行每行占用20個字節,每個索引頁存放400條記錄,則10億數據需要約2500W個索引頁。對于索引IX_LoginDay_UserID(LoginDay,UserID):每天新增的500W新紀錄存放在一起,需要約1.3萬個索引頁來存放,只需要100MB的內存來存放,在數據讀取和寫入時,更多的是順序IO。
對于索引IX_UserID_LoginDay(UserID,LoginDay):每天新增的500W數據需要分散存放到索引的各個頁面中,可能影響到數百萬的索引頁,需要1GB到5GB的內存,在數據讀取和寫入時,更多的是隨機IO。
因此,在不考慮其他因素影響的條件下,針對該場景,索引IX_LoginDay_UserID(LoginDay,UserID)時最佳的。
誤區:在創建復合索引時,很多人會將選擇性較高的列放在前面,解釋:可選擇性是我們在挑選索引鍵時考慮的一個因素,通常會選擇性較高的備選鍵來創建索引,但不意味該鍵就應該放在索引前面。
PS: 在筆者維護的系統中,曾出現過類似問題,在checkpoint時需要寫入上萬個不連續的數據頁,導致很高的磁盤隊列,同時還導致在日志備份還原時消耗大量的時間。
PS2:針對該問題,數據分區和歷史數據定期數據歸檔也是很好的解決辦法。
慣例上圖引狼
圖片來源:http://www.douban.com/photos/photo/353424799/
新聞熱點
疑難解答