Bec*_*uzz 6 database-design sql-server
我是我公司的软件开发人员/架构师,每当我们的主要 DBA 离职时,我偶尔会担任我们的 DBA,所以我想我有点知道我在做什么,但这让我很难找到最佳行动方案。
我们正在努力将单体系统迁移到微服务中。作为这项努力的一部分,我们决定通过 Kafka 使用事件流。我们面临的问题是,在向 Kafka 发送任何内容之前,我们需要能够为我们创建的任何实体提供标识符(Kafka 需要该标识符来保持该实体的任何事件的有序性)。这些标识符需要在托管我们面向客户端的应用程序(网站和 API)的多台机器上创建。所以在这里使用 uniqueidentifier / GUID 似乎是一个合乎逻辑的选择。
如果我们从头开始构建它,我还不会这么担心,因为我们可以将各种实体分离到它们自己的数据存储中(用户可以在一个存储/数据库中,团队可以在另一个中,等等)将保持给定表中的行数有很好的界限,并且查询负载可以分布在多个服务器上。然而,我们当前的系统设计很差,我们系统中的每个实体都位于一个非常非规范化的大表中(因此任何给定的行都可以代表用户、团队、服务等)。这个表有大约 800 万到 900 万行。我们还必须在重写期间使用任何新数据(包括新的 GUID)更新此表。而这正是我所担心的。
我们需要通过这些标识符查找这些实体并保持快速查询。而且我知道 GUID 会产生可怕的键(用于集群或索引),因为它们会导致巨大的碎片、页面拆分等。我们现有系统的一部分使用 GUID 作为实体的查找。有几十万行,索引碎片化到无用的程度,查询被降级为表扫描。我们最终能够更改代码以使用顺序唯一标识符,但这在这里不是一个选项。这让我担心使用随机 GUID 作为标识符将成为性能噩梦。
所以问题是,有没有一种方法可以使用随机 GUID 作为大型表上的非集群键,这样可以快速通过这些 GUID 进行查找?我可以做哪些事情来缓解这个问题?我也对这里的替代解决方案持开放态度,因为我们还没有达到无可挽回的地步。
我会做类似下面的例子。保留一个整数(或 bigint,如果需要)作为标识列和集群键。这将使表整齐排列,最近添加的行在最后,防止表的最大部分(聚集索引)碎片化。
然后在外部 ID(随机 GUID)上创建一个唯一(如果您需要它是唯一的)非聚集索引,并具有更大的填充因子(以最小化重组之间的碎片)。
这应该使对 ExternalID 的查找相当快(窄索引)并保持该索引可快速重新组织。如果需要,您可以使用填充因子为您的日常负载腾出空间。
编辑(建议):您可能需要为此密切关注执行计划。如果您一次请求少量的 ExternalID,那么应该没问题,但是请求大量可能会导致 SQL 认为表扫描是最好的主意;这可能不会。
CREATE TABLE dbo.LargishTable
(
ID INT NOT NULL IDENTITY(1,1)
, ExternalID UNIQUEIDENTIFIER NOT NULL
, OtherColumns NVARCHAR(MAX)
, CONSTRAINT PK_LargishTable PRIMARY KEY CLUSTERED (ID)
)
GO
CREATE UNIQUE NONCLUSTERED INDEX IDXUQ_LargishTable_ExternalID
ON dbo.LargishTable (ExternalID)
WITH (FILLFACTOR=70, SORT_IN_TEMPDB=ON)
GO
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
507 次 |
最近记录: |