设为首页 收藏本站
查看: 1135|回复: 0

[经验分享] SQL Server 索引列的顺序——真的没关系吗

[复制链接]

尚未签到

发表于 2016-11-5 09:00:37 | 显示全部楼层 |阅读模式
  翻译自:http://www.mssqltips.com/sqlservertip/2718/sql-server-index-column-order--does-it-matter/?utm_source=dailynewsletter&utm_medium=email&utm_content=headline&utm_campaign=2012619

问题:
  当设置表的索引时,在性能上有一个微妙的平衡:太多的索引将影响你的INSERT/UPDATE/DELETE操作。但是索引不足又将影响你的SELECT操作。本文将着眼于索引的列顺序和如何影响查询计划及性能。

解决方案:
  示例SQLServer表和数据集:
  -- Tablecreation logic
  CREATE TABLE[dbo].[TABLE1]
  ([col1][int]
NOT NULL,[col2]
[int]NULL,[col3]
[int] NULL,[col4][varchar](50)NULL)
  GO
  CREATE TABLE[dbo].[TABLE2]
  ([col1][int]
NOT NULL,[col2]
[int]NULL,[col3]
[int] NULL,[col4][varchar](50)NULL)
  GO
  ALTER TABLEdbo.TABLE1ADD
CONSTRAINT PK_TABLE1
PRIMARY KEY
CLUSTERED
(col1)
  GO
  ALTER TABLEdbo.TABLE2ADD
CONSTRAINT PK_TABLE2
PRIMARY KEY
CLUSTERED
(col1)
  GO
  --Populate tables
  DECLARE
@val
INT
  SELECT @val=1
  WHILE @val< 1000
  BEGIN
  INSERT
INTO
dbo.Table1(col1,col2,
col3,
col4
)VALUES(@val,@val,@val,'TEST')
  INSERT
INTO
dbo.Table2(col1,col2,
col3,
col4
)VALUES(@val,@val,@val,'TEST')
  SELECT
@val
=@val+1
  END
  GO
  --Create multi-column index on table1
  CREATE NONCLUSTEREDINDEX
IX_TABLE1_col2col3ONdbo.TABLE1(col2,col3)
  WITH (STATISTICS_NORECOMPUTE=OFF,
IGNORE_DUP_KEY =
OFF
,
  ALLOW_ROW_LOCKS=ON,
ALLOW_PAGE_LOCKS =
ON)
  ON [PRIMARY]
  GO
  在运行下面的代码前请先打开执行计划(Ctrl+M)和打开统计IO的语句:SET STATISTICS IO ON

单表查询例子:
  在第一个例子里面,我们将使用在where子句中的一列来查询。第一个查询中where子句的索引使用第二列(col3),第二个查询使用第一列(col2)。注意这里使用了“DBCC DROPCLEANBUFFERS”,用于确保没有缓存带来的影响,代码如下:
DBCC DROPCLEANBUFFERS
GO
SELECT * FROM dbo.TABLE1 WHEREcol3=88
GO
DBCC DROPCLEANBUFFERS
GO
SELECT * FROM dbo.TABLE1 WHEREcol2=88
GO
  执行后查看执行计划如下:
DSC0000.gif
DSC0001.gif
  
  可以看到,第一个查询使用第二列(col3)的索引是在表上执行索引扫描,且没有用到刚才建立的索引。第二个查询使用了表查找,使得在表里只需要使用更少的资源。第一个查询读了6次,而第二个查询只读了4次。
  执行查询后,你应该大概猜到,当表越来越大的时候,性能优势就显现出来了。
  

两表关联查询例子:
  在下一个例子中,查询使用同样的where子句,但增加了一个inner join 关联另外一个表。第一个查询的where子句使用col3,并使用col2来关联表。
  第二个查询的where子句使用col2,并使用col3来关联表。
  同样,先执行DBCC DROPCLEANBUFFERS来确保缓存已经清空。代码如下:

DBCC DROPCLEANBUFFERS
GO
SELECT *
FROM dbo.TABLE1 INNER JOIN
dbo.TABLE2 ON dbo.TABLE1.col2 = dbo.TABLE2.col1
WHERE dbo.TABLE1.col3=255
GO
DBCC DROPCLEANBUFFERS
GO
SELECT *
FROM dbo.TABLE1 INNER JOIN
dbo.TABLE2 ON dbo.TABLE1.col3 = dbo.TABLE2.col1
WHERE dbo.TABLE1.col2=255
GO
  执行计划如下:
  
DSC0002.gif DSC0003.gif
  从执行计划可以看到,当用于关联表的列也在索引中,但不是第一列时,会执行索引扫描。第二个查询中索引的第一列来关列,会使用索引查找。从IO来看,同样索引查找的读次数会更小。

总结:
  从这些例子中,可以看到索引列的顺序对表的查询也有影响。当创建索引时,先确认你总是对尽可能小的集合进行操作,这意味着索引能从where子句中的列开始。另外,对order by子句中的列和SELECT中的列创建覆盖索引也有助于提高查询性能。这样可以不用在查询时执行书签查找。
  在前面提到的,增加太多索引将引起insert/update/delete时对这些索引列的修改。所以,找到平衡点才是最重要的。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-295992-1-1.html 上篇帖子: 实例说明 sql server 多表级联删除的两种方式 下篇帖子: 《SQL Server》之 表的创建和管理
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表