在建立复合索引时,除了考虑索引键的选取外,还需考虑索引键的前后顺序。下面借助一些场景来说解。3d
场景1
表dbo.UserLoginStats记录每一个用户天天的登陆统计,目前表中存放10亿数据,天天新增数据500W(天天每一个用户不多几条条记录),目前系统有用户8000W,有查询:
SELECT * FROM dbo.UserLoginStats
WHERE UserID=@userID
AND LoginDay=@loginDay日志
对于此查询,能够建立索引:blog
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)时最佳的。get
误区:在建立复合索引时,不少人会将选择性较高的列放在前面,
解释:可选择性是咱们在挑选索引键时考虑的一个因素,一般会选择性较高的备选键来建立索引,但不意味该键就应该放在索引前面。登录
PS: 在笔者维护的系统中,曾出现过相似问题,在checkpoint时须要写入上万个不连续的数据页,致使很高的磁盘队列,同时还致使在日志备份还原时消耗大量的时间。bfc
PS2:针对该问题,数据分区和历史数据按期数据归档也是很好的解决办法。
惯例上图引狼