SQL Server创建复合索引时,复合索引列顺序对查询的性能影响

原文: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初步确定满足条件的数据,再进一步的进行过滤

  如果最开始就相对精确地确定了满足查询条件的数据范围,后面可以通过相对较小的代价来最终确认出满足条件的数据

  如果最开始相对模糊地却确定了满足查询条件的数据范围,那么这个过程的代价就相对比较大,虽然后面通过每一个条件的过,结果是一样的

 

  当然这种索引的建立跟数据分布有关,

  但是,我没有下结论说,复合索引一定要按照什么什么顺序来是最好的

  还是那句话:具体问题具体分析,避免经验主义,没有一刀切的手段可以解决所有的问题。

 

总结:

  本文通过一个简单的例子,分析了创建符合索引时,列的顺序对查询的影响,说明在创建索引的时候,不仅仅要考虑在哪些列上创建索引,同时也要注意到,索引列的顺序,是否会对查询产生影响。避免一说到索引,就是“在查询条件上建索引”的暴力做法。

时间: 2024-08-13 11:10:04

SQL Server创建复合索引时,复合索引列顺序对查询的性能影响的相关文章

SqlServer(索引)--创建复合索引时,复合索引列顺序对查询的性能影响[转]

http://www.cnblogs.com/wy123/p/5604400.html SQL Server创建复合索引时,复合索引列顺序对查询的性能影响 说说复合索引 写索引的博客太多了,一直不想动手写,有一下两个原因: 一是觉得有炒剩饭的嫌疑,有兄弟曾说:索引吗,只要在查询条件上建索引就行了,真的可以这么暴力吗? 二来觉得,索引是个非常大的话题,很难概括出所有的情况,你不整出点新意来,倒是有抄袭照搬的嫌疑 既然写了,就写一点稍微不一样的东西出来, 好了,废话打住, /* 20160814备注

SQL Server 2000数据库中如何重建索引

在数据库中创建索引时,查询所使用的索引信息存储在索引页中.连续索引页由从一个页到下一个页的指针链接在一起.当对数据的更改影响到索引时,索引中的信息可能会在数据库中分散开来.重建索引可以重新组织索引数据(对于聚集索引还包括表数据)的存储,清除碎片.这可通过减少获得请求数据所需的页读取数来提高磁盘性能. 在 Microsoft SQL Server 2000 中,如果要用一个步骤重新创建索引,而不想删除旧索引并重新创建同一索引,则使用 CREATE INDEX 语句的 DROP_EXISTING 子

MSSQL-应用案例-SQL Server 2016基于内存优化表的列存储索引分析Web Access Log

问题引入 在日常的网站运维工作中,我们需要对网站客户端访问情况做统计.汇总.分析和报表展示,以数据来全面掌控网站运营和访问情况.当不可预知的意外情况发生时,我们可以快速发现问题以及采取相应的措施.比如:当网站受到黑客攻击时的流量陡增,又或者是网站某个资源发生意外抛异常等情况. 在提供Web服务的服务器上,比如IIS.Apache都存在访问日志记录,这篇是文章是以SQL Server 2016基于内存优化表的列存储索引来分析Apache Web Access Log为例,讲解分析网站访问情况,因此

SQL Server临界点游戏——为什么非聚集索引被忽略!

原文:SQL Server临界点游戏--为什么非聚集索引被忽略! 当我们进行SQL Server问题处理的时候,有时候会发现一个很有意思的现象:SQL Server完全忽略现有定义好的非聚集索引,直接使用表扫描来获取数据.我们来看看下面的表和索引定义: 1 CREATE TABLE Customers 2 ( 3 CustomerID INT NOT NULL, 4 CustomerName CHAR(100) NOT NULL, 5 CustomerAddress CHAR(100) NOT

在 SQL Server 2005 中查询表结构及索引

server|索引 在 SQL Server 2005 中查询表结构及索引 -- 1. 表结构信息查询 -- ========================================================================-- 表结构信息查询 -- 邹建 2005.08(引用请保留此信息)-- ========================================================================SELECT     Tab

在SQL Server 2005中查询表结构及索引

server|索引 在 SQL Server 2005 中查询表结构及索引 -- 1. 表结构信息查询 -- ===================================================-- 表结构信息查询-- 邹建 2005.08(引用请保留此信息)-- ====================================================SELECT     TableName=CASE WHEN C.column_id=1 THEN O.name

SQL SERVER 2005 获取表的所有索引信息以及删除和新建语句

原文:SQL SERVER 2005 获取表的所有索引信息以及删除和新建语句 BEGIN WITH tx AS ( SELECT a.object_id ,b.name AS schema_name ,a.name AS table_name ,c.name as ix_name ,c.is_unique AS ix_unique ,c.type_desc AS ix_type_desc ,d.index_column_id ,d.is_included_column ,e.name AS co

sql server 创建临时表的使用说明_MsSql

临时表产生:A: SELECT INTO和B:CREATE TABLE + INSERT INTO 1. A 要比B 快很多.但是A会锁定tempdb的SYSOBJECTS.SYSINDEXES.SYSCOLUMNS表,在多用户并发的时候,容易产生阻塞其他的进程. 2. 在并发系统中是用B. 大数量的单个语句中,使用A. 创建临时表的方法:        方法一:      create table #临时表名(字段1 约束条件,                       字段2 约束条件,

SQL Server创建数据库和数据表的相关约束实现方法_MsSql

本文分析了SQL Server创建数据库和数据表的相关约束实现方法.分享给大家供大家参考,具体如下: 创建约束语法如下: CREATE DATABASE [test] ON (NAME=N'test',FILENAME=N'd:\SQL2kt_Data\test.mdf',SIZE=3mb,MAXSIZE=UNLIMITED,FILEGROWTH=1MB) LOG ON (NAME=N'test_log',FILENAME=N'd:\SQL2kt_Data\test_log.ldf',SIZE=