SQL Server 索引列的顺序——真的没关系吗

系统 1888 0
原文: SQL Server 索引列的顺序——真的没关系吗

翻译自: 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 TABLE dbo . TABLE1 ADD CONSTRAINT PK_TABLE1 PRIMARY KEY CLUSTERED ( col1 )

GO

ALTER TABLE dbo . TABLE2 ADD 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 NONCLUSTERED INDEX IX_TABLE1_col2col3 ON dbo . 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

执行后查看执行计划如下:

SQL Server 索引列的顺序——真的没关系吗

SQL Server 索引列的顺序——真的没关系吗

可以看到,第一个查询使用第二列(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
  

执行计划如下:

SQL Server 索引列的顺序——真的没关系吗 SQL Server 索引列的顺序——真的没关系吗

从执行计划可以看到,当用于关联表的列也在索引中,但不是第一列时,会执行索引扫描。第二个查询中索引的第一列来关列,会使用索引查找。从IO来看,同样索引查找的读次数会更小。

总结:

从这些例子中,可以看到索引列的顺序对表的查询也有影响。当创建索引时,先确认你总是对尽可能小的集合进行操作,这意味着索引能从where子句中的列开始。另外,对order by子句中的列和SELECT中的列创建覆盖索引也有助于提高查询性能。这样可以不用在查询时执行书签查找。

在前面提到的,增加太多索引将引起insert/update/delete时对这些索引列的修改。所以,找到平衡点才是最重要的。

SQL Server 索引列的顺序——真的没关系吗


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论