SqlServer 聚集索引真的是最好了吗?

--	先模拟环境,后面说明:
USE [Temp]
GO

--	DROP TABLE [TestTab]	TRUNCATE TABLE [TestTab]
CREATE TABLE [dbo].[TestTab](
	[UserAcount]	[varchar](50) NOT NULL,
	[UserName]		[varchar](50) NOT NULL,
	[crdatetime]	[datetime] NOT NULL,
	[value]		[numeric](18, 4) NULL,
	[Info]		[varchar](50) NULL,
	CONSTRAINT [PK_TestTab] PRIMARY KEY CLUSTERED ([UserAcount] ASC,[UserName] ASC)
) ON [PRIMARY]
GO

--	DROP VIEW [VTestTab]
CREATE VIEW [dbo].[VTestTab]
AS
SELECT [UserAcount],[UserName],[crdatetime],[value],[Info]
FROM [dbo].[TestTab]
WHERE [UserAcount] = CURRENT_USER
GO

--	插入测试数据: 2538 行
INSERT INTO [TestTab]([UserAcount],[UserName],[crdatetime],[value],[Info])
SELECT CURRENT_USER,name,MAX(crdate),FLOOR(RAND(ABS(CHECKSUM(NEWID())))*1000),NULL
FROM master.sys.sysobjects
WHERE LEN(name)>1 AND LEN(name)<50
GROUP BY name

实际环境:

上面插入的数据是一个用户(CURRENT_USER)的数据,表中还存在更多用户.

由于是按用户划分管理(分库分区等)的,所以列名称[UserAcount]作为聚集索引首先放在第一列

因此,用户都是访问视图[VTestTab],查看到的只有用户自己的数据.

现有以下这个查询:

SELECT * FROM [VTestTab]
WHERE [crdatetime] = '2011-06-17 03:18:08.647'

看执行计划,查询是走索引的.因为视图将转变为对表的查询,如下:

SELECT * FROM [TestTab]
WHERE [UserAcount] = CURRENT_USER
AND [crdatetime] = '2011-06-17 03:18:08.647'

开始以为,这个使用聚集索引已无法优化了.但是想想,按聚集索引的原理,使用聚集索引查找,表中[UserAcount] = CURRENT_USER 的数据将全部符合,也就是聚集索引将会把当前用户的数据全部查询一遍,即按主键列[UserAcount]查找一遍,并没有准确定位到时间点‘2011-06-17 03:18:08.647‘这行

所以,现在测试看看到底聚集索引到底查询了多少行!

--使用序列化查看,在事务结束前查看锁情况。
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRAN
	SELECT * FROM [VTestTab]
	WHERE [crdatetime] = '2011-06-17 03:18:08.647'

	select resource_type,resource_description,request_mode,request_status,request_type,request_lifetime
	from sys.dm_tran_locks where resource_database_id=DB_ID() and [email protected]@SPID
COMMIT TRAN

可以看到,整个哈希键都查找了一遍.有页锁(PAGE:IS),键范围锁(KEY:RangeS-S)。把符合索引键[UserAcount]的用户到查询出来了!但最终只返回一行。

如果表中的数据达到了锁升级要求(表行数五六千以上),对表将升级为共享锁!

既然不是最好的,那就考虑另外的索引定位了!

当前聚集索引键列为:([UserAcount],[UserName])

现考虑4种索引创建方法,到底哪种比较较好!~

--	DROP INDEX IX_TestTab ON [TestTab]
CREATE NONCLUSTERED INDEX IX_TestTab ON [TestTab]([UserAcount],[crdatetime])

CREATE NONCLUSTERED INDEX IX_TestTab ON [TestTab]([crdatetime])

CREATE NONCLUSTERED INDEX IX_TestTab ON [TestTab]([crdatetime],[UserAcount])

CREATE NONCLUSTERED INDEX IX_TestTab ON [TestTab]([crdatetime])INCLUDE([value],[Info])
--第一种:
CREATE NONCLUSTERED INDEX IX_TestTab ON [TestTab]([UserAcount],[crdatetime])

这种还是使用聚集索引,并没有用到新的索引,因为新的索引第一个键列为 [UserAcount],与聚集索引一样,所以只要有[UserAcount] ,查询就使用聚集索引了!这个索引加上去也是白加。

--第二种:
CREATE NONCLUSTERED INDEX IX_TestTab ON [TestTab]([crdatetime])

这个查询使用了索引查找,直接按列 [crdatetime]  查询,但是其他不包含在索引的列,使用了键查找。还得在索引子页中查找非索引列。并且锁少了很多!!

--第三种:
CREATE NONCLUSTERED INDEX IX_TestTab ON [TestTab]([crdatetime],[UserAcount])

这种查询的执行计划与上面的一致,因为缓存计划进行了参数化,两者执行语句一样,使用的索引不影响执行计划。而且锁定的资源几乎一样。这个索引的另一列 [UserAcount] 其实是多余了,因为非聚集索引中都会包含聚集索引的键列。所以这个索引的第二列[UserAcount]可以去掉了。

--第四种:
CREATE NONCLUSTERED INDEX IX_TestTab ON [TestTab]([crdatetime])INCLUDE([value],[Info])

这个锁定的资源就比较直接了!~完全使用非聚集索引查找,查询直接定位到数据行!~

所以对于聚集索引,应尽量使用唯一列作为聚集索引,或者最为键列的数据尽量不要重复,这样才能以最快速度定位到行。若没有唯一列,像上面的例子中,聚集索引和另一个比较有效的列作为组合索引聚集索引!~

时间: 2024-12-05 21:22:58

SqlServer 聚集索引真的是最好了吗?的相关文章

SQLSERVER聚集索引与非聚集索引的再次研究(下)

原文:SQLSERVER聚集索引与非聚集索引的再次研究(下) SQLSERVER聚集索引与非聚集索引的再次研究(下) 上篇主要说了聚集索引和简单介绍了一下非聚集索引,相信大家一定对聚集索引和非聚集索引开始有一点了解了. 这篇文章只是作为参考,里面的观点不一定正确 上篇的地址:SQLSERVER聚集索引与非聚集索引的再次研究(上) 下篇主要说非聚集索引 先上非聚集索引的结构图 先创建Department8表 1 --非聚集索引 2 USE [pratice] 3 GO 4 5 CREATE TAB

SQLSERVER聚集索引与非聚集索引的再次研究(上)

原文:SQLSERVER聚集索引与非聚集索引的再次研究(上) SQLSERVER聚集索引与非聚集索引的再次研究(上) 上篇主要说聚集索引 下篇的地址:SQLSERVER聚集索引与非聚集索引的再次研究(下) 由于本人还是SQLSERVER菜鸟一枚,加上一些实验的逻辑严谨性, 单写<SQLSERVER聚集索引与非聚集索引的再次研究(上)>就用了12个小时,两篇文章加起来最起码写了20个小时, 本人非常非常用心的努力完成这两篇文章,希望各位看官给点意见o(∩_∩)o 为了搞清楚索引内部工作原理和结构

SqlServer 聚集索引重建后变换列位置统计信息列名不变

原本是使用聚集索引主键发现的,确认不是主键问题,是聚集索引问题. version:Microsoft SQL Server 2008 R2 (SP1) -- 创建测试表 -- drop table [TestTable] create table [dbo].[TestTable]( [id] [int] not null, [name] [varchar](20) not null ) go -- 插入数据 insert into [TestTable]([id],[name]) select

【sqlserver】索引

索引概念 索引是与视图关联的磁盘或内存中结构,可以加快从表或视图中的检索速度.索引包含由表或视图中的一列或多列生成的键. 索引特点 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性. 可以大大加快数据的检索速度,这也是创建索引的最主要的原因. 可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义. 在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间. 通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能. 索引不足 创建索引和维护索引要

SqlServer 创建聚集索引与非聚集索引处理千万条数据的优化,以及之间的区别

在以下的文章中,我将以"办公自动化"系统为例,探讨如何在有着1000万条数据的MS SQL SERVER数据库中实现快速的数据提取和数据分页.以下代码说明了我们实例中数据库的"红头文件"一表的部分数据结构: CREATE TABLE [dbo].[TGongwen] ( --TGongwen是红头文件表名 [Gid] [int] IDENTITY (1, 1) NOT NULL , --本表的id号,也是主键 [title] [varchar] (80) COLLA

SqlServer中创建非聚集索引和非聚集索引

聚集索引与非聚集索引,其实已经有很多的文章做过详细介绍. 非聚集索引 简单来说,聚集索引是适合字段变动不大(尽可能不出现Update的字段).出现字段重复率小的列,因为聚集索引是对数据物理位置相同的索引,所以一张表中只能出现一个聚集索引. 聚集索引的特征:代表全部数据存储的位置索引,不能经常去更新这个字段,最好不出现重复. 聚集索引 非聚集索引也有很多人叫法上细分为唯一索引.全文索引.普通索引,我们在进项条件查询时,作为条件过滤的字段通常被设置为非聚集索引,这样就不需要去读取原始记录,直接查询索

SQLServer之创建唯一聚集索引

创建唯一聚集索引典型实现 唯一索引可通过以下方式实现: PRIMARY KEY 或 UNIQUE 约束 在创建 PRIMARY KEY 约束时,如果不存在该表的聚集索引且未指定唯一非聚集索引,则将自动对一列或多列创建唯一聚集索引. 主键列不允许空值. 在创建 UNIQUE 约束时,默认情况下将创建唯一非聚集索引,以便强制 UNIQUE 约束. 如果不存在该表的聚集索引,则可以指定唯一聚集索引. 有关详细信息,请参阅 Unique Constraints and Check Constraints

Sql Server之旅——第三站 解惑那些背了多年聚集索引的人

说到聚集索引,我想每个码农都明白,但是也有很多像我这样的猥程序员,只能用死记硬背来解决这个问题,什么表中只能建一个聚集索引, 然后又扯到了目录查找来帮助读者记忆....问题就在这里,我们不是学文科,,,不需要去死记硬背,,,我们需要的就是能看到在眼里面的 真实东西.....我们都喜欢聚集索引,因为它能够把无序的堆表记录变成有序,还玩起了B树...这样就把复杂度从N降低到了LogMN... 这样的话逻辑读,物理读就下来了. 一:现象 1:无索引的情况 还是老规矩,看个例子感受下,首先我有一个Pro

聚集索引与非聚集索引

转自:聚集索引和非聚集索引(整理) 官方说法: 聚集索引 一种索引,该索引中键值的逻辑顺序决定了表中相应行的物理顺序. 聚集索引确定表中数据的物理顺序.聚集索引类似于电话簿,后者按姓氏排列数据.由于聚集索引规定数据在表中的物理存储顺序,因此一个表只能包含一个聚集索引.但该索引可以包含多个列(组合索引),就像电话簿按姓氏和名字进行组织一样. 聚集索引对于那些经常要搜索范围值的列特别有效.使用聚集索引找到包含第一个值的行后,便可以确保包含后续索引值的行在物理相邻.例如,如果应用程序执行 的一个查询经