Sql 从群集复合密钥移动到顺序整数群集密钥时性能下降
我有一个主键(primkey)的表,由(用户名VARCHAR(50)、年龄INT、日期时间)组成。然后在这一天为用户索引一组数据。一般来说,我会为用户名请求所有数据 如果我错了,请纠正我-这里的集群工作得很好,因为它将首先基于USER\u NAME进行集群,因此将USER\u NAME=JOHN\u SMITH的所有数据放在一起。然后,它将根据年龄等进行聚类。因为我请求特定用户的所有数据,这意味着IO得到了优化,即我读取的页面数量最少,而查询请求的数据量较大,因此IO绑定速度最快 我目前计划用uid替换(用户名,年龄),而顺序递增的数字是(用户名,年龄)和uid之间的随机映射。这当然也会将primkey更改为(UID INT,DATE DATETIME),因为UID只是一个数字,例如(JOHN_-SMITH,24)可能是123124,(JOHN_-SMITH,25)可能是352431,就我所见,集群变得毫无意义。我的意思是,虽然旧primkey中的(JOHN_SMITH,24)和(JOHN_SMITH,25)显然是连续两年内同一用户的数据,DB会将数据紧密地聚集在磁盘上,但数字123124和352431不包含任何有关引用数据的信息。也就是说,旧的primkey具有结构,新的primkey没有结构,也没有关于引用数据的隐式信息 一种解决方案是在UID中实现某种寻址方案(例如IPv4样式,但要简单得多)——即每个用户名都有150个UID的保留空间,也就是说,如果JOHN_SMITH的UID为0,JOHN_SMYTH将获得至少150个UID,并且0-149是为(用户名=JOHN_SMITH,年龄=?)组合保留的 我实际上不想采用寻址方案。如果您对此有任何想法(包括我的理论是否正确),我们将不胜感激Sql 从群集复合密钥移动到顺序整数群集密钥时性能下降,sql,sql-server,database,database-design,Sql,Sql Server,Database,Database Design,我有一个主键(primkey)的表,由(用户名VARCHAR(50)、年龄INT、日期时间)组成。然后在这一天为用户索引一组数据。一般来说,我会为用户名请求所有数据 如果我错了,请纠正我-这里的集群工作得很好,因为它将首先基于USER\u NAME进行集群,因此将USER\u NAME=JOHN\u SMITH的所有数据放在一起。然后,它将根据年龄等进行聚类。因为我请求特定用户的所有数据,这意味着IO得到了优化,即我读取的页面数量最少,而查询请求的数据量较大,因此IO绑定速度最快 我目前计划用u
DECLARE @testtable TABLE
(
uid INT,
startdate DATETIME,
enddate DATETIME
);
INSERT INTO @testtable
(
uid,
startdate,
enddate
)
VALUES
(1233890,'01-Jul-2017 00:00:00','15-Jul-2017 23:59:59'),
(1523420,'01-Jul-2018 00:00:00','15-Jul-2018 23:59:59')
SELECT UID, [DATE], [WAKEUP_TIME]
FROM dbo.USERS user
INNER JOIN @testtable cont
ON user.uid = cont.uid
AND user.DATE >= cont.startdate
AND user.DATE <= cont.enddate
WHERE user.USER_NAME = 'John'
ORDER BY 2 ;
DECLARE@testtable
(
uid INT,
开始日期时间,
结束日期日期时间
);
插入到@testtable中
(
uid,
开始日期,
结束日期
)
价值观
(1233890,'2017年7月1日00:00:00','2017年7月15日23:59:59'),
(1523420,'2018年7月1日00:00:00','2018年7月15日23:59:59')
选择UID、[日期]、[唤醒时间]
来自dbo.USERS
内部联接@testtable cont
ON user.uid=cont.uid
和user.DATE>=cont.startdate
和user.DATE首先,您猜测的select
查询的损失是insert
s和delete
s的收益。新记录只需添加到表的“末尾”,不需要拆分页面
第二,如果可以,您可能想尝试新的结构。例如,如果整个表都能放入内存,那么从多个页面读取数据与从单个页面读取数据不会有太大的区别
最后,SQL Server不要求将主键用于群集。您只有一个群集键。但您可以引入一个新的唯一id,使其成为主键,并仍然按其他列进行群集。您似乎在按用户名、年龄
和日期
的范围进行平等筛选。如果替换>用户名、年龄
通过一个新的人工值
uid,则基于相等过滤的索引搜索仍然有效
从您发布的查询中可以看出,SQL Server可能会通过反复探测用户来执行它。对于@testtable
中的每个项目,都会执行一次。这是作为嵌套循环联接完成的
这是相同的索引使用模式和查询计划形状。但是您是正确的,AGE
的不同值现在将基本上随机地分布在索引中,而之前相同用户的所有AGE
值都是共位的
这肯定会导致更多的磁盘寻道,从而导致性能损失。您指出,大多数表不会缓存在RAM中。因此,索引中必须访问的点数对性能非常重要(正如您正确识别的)
当然,最简单的解决方案是不采用新的uid
列。但我认为您有理由这样做
您可以通过将AGE
值冗余地打包到最后一个字节(例如,db\u uid=sequential\u id\u for_user\u name*256+AGE
)来实现一个简单的“寻址方案”。您需要注意不要溢出
这将物理地将相关的年龄值组合在一起,很可能导致加速
也考虑使用<代码> BigInt/Cude>有更多的空间来对数据进行编码。
谢谢-(1)我选择了性能约束,不特别关心插入和删除。(2)表很大(几十个GBS)。(3)我知道,我也使用了一个聚集索引。不管查询关键字是不是PRIMKY(例如索引)。,您对上述性能僵局有何看法?哪些重要的select查询应该保持快速?@usr请参阅原始问题中的修正案