SQL Server创建复合索引时,复合索引列顺序对查询的性能影响
说说复合索引
写索引的博客太多了,一直不想动手写,有一下两个原因:
一是觉得有炒剩饭的嫌疑,有兄弟曾说:索引吗,只要在查询条件上建索引就行了,真的可以这么暴力吗?
二来觉得,索引是个非常大的话题,很难概括出所有的情况,你不整出点新意来,倒是有抄袭照搬的嫌疑
既然写了,就写一点稍微不一样的东西出来,
好了,废话打住,开搞
搭建测试环境:
创建一张表,模拟实际业务中的一个表,往里面填入数据,
时间字段上,相对按照时间均匀地填充,其他字段以GUID填充

Create table BusinessInfoTable
(
BuniessCode1 varchar(50),
BuniessCode2 varchar(50),
BuniessCode3 varchar(50),
BuniessCode4 varchar(50),
BuniessStatus1 tinyint,
BuniessStatus2 tinyint,
BuniessDateTime1 Datetime,
BuniessDateTime2 Datetime,
OtherColumn1 varchar(50),
OtherColumn2 varchar(50),
OtherColumn3 varchar(50)
) declare @i int=0
while @i<1000000
begin
insert into BusinessInfoTable
values
(
NEWID(),NEWID(),NEWID(),NEWID(),RAND()*100,RAND()*100,
DATEADD(MI,@i,GETDATE()),DATEADD(MI,@i,GETDATE()),NEWID(),NEWID(),NEWID()
)
set @i=@i+1
end

现在有这么一个查询(实际上查询远比这个复杂,我简化一点,不要说我刻意造环境)

select OtherColumn2,
BuniessStatus1,
BuniessStatus2,
BuniessDateTime1,
BuniessDateTime2
from BusinessInfoTable
where BuniessDateTime1 between '2016-6-21' and '2016-6-28'
and BuniessDateTime2 between '2016-6-21' and '2016-6-28'
and BuniessStatus1 = 55
and BuniessStatus2 = 66

郑重的说明一点:
暂时不考虑聚集索引,毕竟一个表上只能有一个聚集索引,
别人也不是傻子,不会轻易去建聚集索引,聚集索引早被占用了
既然被占用了,我的原则是一般不去动别人现有的东西的,比如别人建了聚集索引,你给人家删了,根据自己的情况建聚集索引
这不是找骂么
有经验的你一定考虑符合索引了,同时考虑到为避免Key Lookup导致的书签查找,我们把查询索要的OtherColumn2列include进来
比如这样
CREATE NONCLUSTERED INDEX IDX_1 ON BusinessInfoTable
(BuniessStatus1,BuniessStatus2,BuniessDateTime1,BuniessDateTime2)
INCLUDE(OtherColumn2)
或者这样,只是索引列顺序不一样
CREATE NONCLUSTERED INDEX IDX_1 ON BusinessInfoTable
(BuniessDateTime1,BuniessDateTime2,BuniessStatus1,BuniessStatus2)
INCLUDE(OtherColumn2)
当然可以随意调整四个列的顺序,我就不过多地做演示了,有兴趣的自己试
这里的前导列的顺序并不会影响到索引的使用,查询的时候都是非聚集索引Seek,绝对的
那么问题来了,完全一样的查询条件,结果一样,使用不同的索引,索引的区别仅仅是列顺序不一样,其代价一样吗,先猜测一下,有区别吗?
同样查询,使用不同索引的结果(分别是上面的IDX_1和IDX_2):
下面看图说话

看看IO情况

原因分析
看来是有点差别吧,好似乎这个差别还真不小(以往写文章,我测试环境弄不好,对比出来的效果不明显,感觉没啥说服力,这次对比还是比较明显的)
究竟原因在何?
索引是以平衡树(B树)的方式存在的,复合索引的列的顺序决定了B树的信息的存储的顺序
如果是以BuniessStatus1列为前导列,因为BuniessStatus1分布的范围(相对)较小,
这样在查询的时候通过BuniessStatus1=55就可以过滤出来一个比较小的结果集,后面依次用其他条件过滤就相对较快了
比如BuniessStatus1=55过滤出来符合条件的数据有5条,
加上BuniessStatus2 BuniessDateTime1 BuniessDateTime2 这三个条件再过滤,出来一条数据。
如果BuniessDateTime1 是索引的前导列,用BuniessDateTime1 between '2016-6-21' and '2016-6-28'过滤
可能会有10000条数据,然后依次再用 BuniessDateTime2,BuniessStatus1, BuniessStatus2过滤
最后也只有一条符合条件的数据。
差别就在于:一开始的过滤条件,决定了查询多少page初步确定满足条件的数据,再进一步的进行过滤
如果最开始就相对精确地确定了满足查询条件的数据范围,后面可以通过相对较小的代价来最终确认出满足条件的数据
如果最开始相对模糊地却确定了满足查询条件的数据范围,那么这个过程的代价就相对比较大,虽然后面通过每一个条件的过,结果是一样的
当然这种索引的建立跟数据分布有关,
但是,我没有下结论说,复合索引一定要按照什么什么顺序来是最好的
还是那句话:具体问题具体分析,避免经验主义,没有一刀切的手段可以解决所有的问题。
SQL Server创建复合索引时,复合索引列顺序对查询的性能影响的更多相关文章
- SQL Server 创建表 添加主键 添加列常用SQL语句
--删除主键 alter table 表名 drop constraint 主键名 --添加主键 alter table 表名 add constraint 主键名 primary key(字段名1, ...
- SQL Server 创建表 添加主键 添加列常用SQL语句【转】
--删除主键alter table 表名 drop constraint 主键名--添加主键alter table 表名 add constraint 主键名 primary key(字段名1,字段名 ...
- SQL Server创建表超出行最大限制解决方法
问题的现象在创建表A的时候,出现“信息 511,级别 16,状态 1,第 5 行 无法创建大小为 的行,该值大于允许的最大值 8060.”的信息提示.很奇怪,网上查了一下,是因为要插入表的数据类型的 ...
- SQL Server 创建索引方法
转自 <SQL Server 创建索引的 5 种方法> 地址:https://www.cnblogs.com/JiangLe/p/4007091.html 前期准备: create tab ...
- SQL Server创建索引
原文:SQL Server创建索引 什么是索引 拿汉语字典的目录页(索引)打比方:正如汉语字典中的汉字按页存放一样,SQL Server中的数据记录也是按页存放的,每页容量一般为4K .为了加快查找的 ...
- SQL Server 2005 中的分区表和索引
SQL Server 2005 中的分区表和索引 SQL Server 2005 69(共 83)对本文的评价是有帮助 - 评价此主题 发布日期 : 3/24/2005 | 更新 ...
- SQL Server调优系列基础篇 - 索引运算总结
前言 上几篇文章我们介绍了如何查看查询计划.常用运算符的介绍.并行运算的方式,有兴趣的可以点击查看. 本篇将分析在SQL Server中,如何利用先有索引项进行查询性能优化,通过了解这些索引项的应用方 ...
- SQL Server 调优系列基础篇 - 索引运算总结
前言 上几篇文章我们介绍了如何查看查询计划.常用运算符的介绍.并行运算的方式,有兴趣的可以点击查看. 本篇将分析在SQL Server中,如何利用先有索引项进行查询性能优化,通过了解这些索引项的应用方 ...
- SQL Server的唯一键和唯一索引会将空值(NULL)也算作重复值
我们先在SQL Server数据库中,建立一张Students表: CREATE TABLE [dbo].[Students]( ,) NOT NULL, ) NULL, ) NULL, [Age] ...
随机推荐
- 从ICassFactory为CLSID为{17BCA6E8-A950-497E-B2F9-AF6AA475916F}的COM组件创建实例失败问题解决方法
从ICassFactory为CLSID为{17BCA6E8-A950-497E-B2F9-AF6AA475916F}的COM组件创建实例失败,原因是出现以下错误:c001f011.(Microsoft ...
- Win10光驱不见了
1. 网上教程试了很多,如下: http://jingyan.baidu.com/article/02027811656a8b1bcd9ce570.html http://jingyan.todgo. ...
- Makefile 使用总结
参考: [1]. Makefile 使用总结. http://www.cnblogs.com/wang_yb/p/3990952.html
- onethink入门笔记(一)
由于公司需求所以大概花了一个星期搞了一个一个基于onethink的数据管理平台demo不得不说onethink这个基于thinkphp3.2.3的框架还是很棒的 让我这个没基础过php的人也能在一星期 ...
- 使用yum安装应用程序时候,报错:[Errno 14] PYCURL ERROR 7 - "Failed to connect to 2001:da8:8000:6023::230: 网络不可达"
使用yum安装应用程序时候,报错:[Errno 14] PYCURL ERROR 7 - "Failed to connect to 2001:da8:8000:6023::230: 网络不 ...
- PHP中类自动加载的方式
最近在学习composer,发现从接触PHP到现在已经遇到了三种关于PHP中类的自动加载方式,这其中包括PHP自带的类的自动加载方式.PHP的第三方的依赖管理工具composer的加载方式以及PHP的 ...
- 使用Birt开发报表
间隔一段时间未使用Birt开发报表后,本文章记录Birt开发报表的常遇到的开发问题及解决措施,方便自己和园内其他朋友学习. 一.Birt连接数据库配置 1.连接DB2数据库: 1.1.birt的数据连 ...
- IS A 和 HAS A的区别
IS A:一般是用作继承或者接口类.比如:中国人和外国人都是人,重点在:是一个... . HAS A:一般用作对象和他的成员的从属关系.比如:中国人和外国人都有眼睛.耳朵.嘴巴.重点在:有一个... ...
- Foundation ----->NSSet
1.集合类 NSString *s1 = @"zhangsan"; NSString *s2 = @"lisi"; NSString * ...
- <a>标签中的href="javascript:;"是什么意思?
例子:<a href="javascript:;">我的大学</a> javascript: 是一个伪协议 javascript:是表示在触发<a&g ...