关于sql server:GUID作为主键-脱机OLTP

关于sql server:GUID作为主键-脱机OLTP

GUIDs as Primary Keys - Offline OLTP

我们正在设计通常是OLTP(想想:采购系统)的应用程序。 但是,这一点尤其需要某些用户脱机,因此他们需要能够将DB下载到他们的计算机上,在该计算机上工作,然后在他们进入LAN后再同步回去。

我想指出的是,我知道这之前已经做过,只是我没有使用这种特定模型的经验。

我想到的一个想法是使用GUID作为表键。 因此,例如,一个采购订单将没有数字(自动数字),而是一个GUID,以便每个脱机客户端都可以生成这些数字,并且当我重新连接到数据库时,我不会发生冲突。

由于某种原因,这是一个坏主意吗?
通过GUID键访问这些表的速度会变慢吗?

您是否有使用这类系统的经验? 您如何解决这个问题?

谢谢!
丹尼尔


将Guid用作主键是可以接受的,并且出于与考虑它们相同的原因,这被认为是相当标准的做法。它们可能会被过度使用,从而使调试和管理工作变得有些繁琐,因此请尽可能使它们远离代码表和其他参考数据。

您必须关心的是人类可读的标识符。不能与他人交换Guid-如果您是Guid,可以想象通过电话确认您的订单号吗?因此,在离线情况下,您可能仍需要生成一些内容-例如发布者(工作站/用户)ID和一些序列号,因此订单号可能是123-5678-。

但是,这可能无法满足具有序号的业务要求。实际上,法规要求可能会产生影响-有些法规(可能是SOX)要求发票编号是连续的。在这种情况下,可能需要生成某种形式的编号,该编号在以后的系统同步时固定下来。您可能会发现具有OrderId(Guid),OrderNo(int),ProformaOrderNo(varchar)的表-可能会增加一些复杂性。

至少将Guid作为主键意味着,当同步最终发生时,您不必进行大量的级联更新-您只需更新人类可读的数字即可。


@SqlMenace

There are other problems with GUIDs, you see GUIDs are not sequential, so inserts will be scattered all over the place, this causes page splits and index fragmentation

不对。主键!=聚集索引。

如果聚集索引是另一列(想到" inserted_on"),则插入将是连续的,并且不会发生页面拆分或过多的碎片。


这是GUID的完美使用。唯一的缺点是在INT上使用GUID时会有些复杂,并且大小会有所不同(16字节对4字节)。

我认为这些都不是什么大问题。


我只想向您指出Sequential Guid相对于标准Guid的性能改进是什么?

为了便于阅读,请考虑分配机器ID,然后使用这些机器的顺序号。但是,这将需要管理机器ID的分配。可以在一两列中完成。

我个人很喜欢SGUID的答案。


确保利用guid.comb-处理索引工作。如果之后您要处理性能问题,那么您很快就会成为扩展专家。

使用GUID的另一个原因是启用数据库重构。假设您决定对客户实体应用多态性或继承性。现在,您希望客户和员工从Person派生并让他们共享一个表。具有真正唯一的标识符使数据迁移变得简单。没有要处理的序列或整数标识字段。


您是正确的,这是一个老问题,它有两个规范的解决方案:

  • 使用唯一标识符作为主键。请注意,如果您担心可读性,可以滚动自己的唯一标识符而不是使用GUID。唯一标识符将使用有关日期和机器的信息来生成唯一值。

  • 使用"演员" +标识符的复合键。每个用户都会获得一个数字演员ID,新插入的行的键将使用演员ID以及下一个可用的标识符。因此,如果两个参与者都插入ID为" 100"的新行,则不会违反主键约束。

就个人而言,我更喜欢第一种方法,因为我认为复合键作为外键确实很乏味。我认为对人类可读性的抱怨被夸大了-最终用户无论如何都不必了解您的钥匙!


Will access to these tables through
the GUID key be slow?

GUID还有其他问题,您会看到GUID不是连续的,因此插入将分散在各处,这会导致页面拆分和索引碎片

在SQL Server 2005中,MS引入了NEWSEQUENTIALID()来解决此问题,唯一的问题是您只能在表中使用NEWSEQUENTIALID作为默认值


@Portman默认情况下PK ==聚簇索引,创建主键约束将自动创建聚簇索引,如果您不希望聚簇索引,则需要指定非聚簇索引。


首先想到的是:MS是否没有设计DataSet和DataAdapter模型来支持这样的方案?

我相信我读过MS将其ADO记录集模型更改为当前的DataSet模型,因此它在离线状态下也能很好地工作。还有针对ADO.NET的同步服务

我相信我已经看过利用DataSet模型的代码,该模型也使用外键,并且在使用DataAdapter时它们仍然可以完美同步。虽然没有尝试Sync Services,但我认为您也可以从中受益。

希望这可以帮助。


我将开始为此目的查看SQL Server Compact Edition!它可以帮助您解决所有问题。

SQL Server 2005 Compact Edition的数据存储体系结构

专为

Field force applications (FFAs). FFAs
usually share one or more of the
following attributes

They allow the user to perform their
job functions while disconnected from
the back-end network—on-site at a
client location, on the road, in an
airport, or from home.

FFAs are usually designed for
occasional connectivity, meaning that
when users are running the client
application, they do not need to have
a network connection of any kind. FFAs
often involve multiple clients that
can concurrently access and use data
from the back-end database, both in a
connected and disconnected mode.

FFAs must be able to replicate data
from the back-end database to the
client databases for offline support.
They also need to be able to replicate
modified, added, or deleted data
records from the client to the server
when the application is able to
connect to the network


@西蒙

您提出了很好的观点。我已经在考虑脱机时会生成的"临时""人类可读"数字,这些数字会在同步时重新创建。但我想避免使用外键等。


如果您的数据库足够小,可以下载到笔记本电脑并脱机使用,则您不必担心int和Guid之间的性能差异。但是,请不要低估在开发系统和对系统进行故障排除时int有多有用!无论是否使用Guid,您可能都需要提出一些相当复杂的导入/同步逻辑,因此它们可能没有您想的那么有用。


当我们不得不将两个数据库合并为一个数据库时,使用GUID节省了我们很多工作。


后端将是SQL Server 2005
前端/应用逻辑将是.Net

除了GUID,您是否可以想到其他方法来解决脱机计算机将新数据同步回中央数据库时发生的"合并"问题?
我的意思是,如果键是INT,则在基本导入时我必须重新编号所有内容。 GUID将使我免于此。


引导肯定会比标准整数键慢(并且使用更多的内存),但是这是否是一个问题取决于系统将看到的负载类型。根据您的后端数据库,索引guid字段可能会出现问题。

使用guid可以简化一整类问题,但是您要为此付出代价的是性能和可调试性-在那些测试查询中键入guid会很快变老!


推荐阅读