我们正在致力于设计一个典型的 OLTP 应用程序(想想:采购系统)。然而,这个特别需要一些用户处于离线状态,因此他们需要能够将数据库下载到他们的计算机上,对其进行处理,然后在连接到 LAN 后同步回来。

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

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

出于某种原因,这是一个坏主意吗?通过GUID键访问这些表会不会很慢?

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

谢谢!
丹尼尔

有帮助吗?

解决方案

使用 Guid 作为主键是可以接受的,并且被认为是相当标准的做法,原因与您考虑使用它们的原因相同。它们可能会被过度使用,这会使调试和管理变得有点乏味,因此如果可能的话,请尽量将它们排除在代码表和其他参考数据之外。

您必须关心的是人类可读的标识符。人们无法交换指南 - 如果是指南,您能想象尝试通过电话确认您的订单号吗?因此,在离线场景中,您可能仍然需要生成 某物 - 就像发布者(工作站/用户)id 和一些序列号,因此订单号可能是 123-5678 -。

然而,这可能无法满足具有序列号的业务需求。事实上,监管要求可能会产生影响——一些法规(可能是 SOX)要求发票号码是连续的。在这种情况下,可能需要生成一种形式编号,该编号稍后在系统同步时修复。您可能会得到包含 OrderId (Guid)、OrderNo (int)、ProformaOrderNo (varchar) 的表 - 可能会出现一些复杂性。

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

其他提示

@SqlMenace

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

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

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

这是 GUID 的完美使用。唯一的缺点是使用 GUID 比使用 INT 稍微复杂一些,并且大小略有差异(16 字节与 4 字节)。

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

通过GUID密钥访问这些表是否会很慢?

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

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

你是对的,这是一个老问题,它有两个规范的解决方案:

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

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

就我个人而言,我更喜欢第一种方法,因为我认为复合键作为外键确实很乏味。我认为对人类可读性的抱怨被夸大了——无论如何,最终用户不应该知道关于你的密钥的任何信息!

确保使用 guid.comb - 负责索引工作。如果您之后正在处理性能问题,那么您很快就会成为扩展方面的专家。

使用 GUID 的另一个原因是启用数据库重构。假设您决定对您的 Customers 实体应用多态性或继承或其他任何内容。您现在希望 Customers 和Employees 派生自Person 并让他们共享一个表。拥有真正唯一的标识符使数据迁移变得简单。没有序列或整数标识字段可供对抗。

我只是要指出 Sequential Guid 相对于标准 Guid 有哪些性能改进?, ,其中涵盖了 GUID 讨论。

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

不过,我个人很喜欢 SGUID 的答案。

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

使用 guid 可以简化一整类问题,但是你要为性能和可调试性付出代价——在这些测试查询中输入 guid 会很快变得过时!

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

除了 GUID 之外,您还能想到其他方法来解决离线计算机将新数据同步回中央数据库时发生的“合并”吗?
我的意思是,如果键是 INT,我基本上在导入时必须重新编号所有内容。GUID 会让我省去这个麻烦。

当我们必须将两个数据库合并为一个时,使用 GUID 为我们节省了大量工作。

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

@西蒙,

你提出了非常好的观点。我已经在考虑离线时生成的“临时”“人类可读”数字,并在同步时重新创建。但我想避免使用外键等。

为此我将开始考虑 SQL Server Compact Edition!它有助于解决您的所有问题。

SQL Server 2005 Compact Edition 的数据存储架构

它专门设计用于

现场部队应用程序 (FFA)。FFA通常共享以下一个或多个属性

他们允许用户在与后端网络断开连接时(在客户位置,道路,机场或家里)执行其工作功能。

FFA通常是为偶尔连接而设计的,这意味着当用户运行客户端应用程序时,他们不需要具有任何类型的网络连接。FFA通常涉及多个客户端,这些客户端可以在连接和断开的模式下同时访问和使用后端数据库中的数据。

FFA必须能够将数据库从后端数据库复制到客户端数据库以进行离线支持。当应用程序能够连接到网络时,他们还需要能够从客户端复制修改,添加或删除的数据记录

我首先想到的是:MS不是设计了DataSet和DataAdapter模型来支持这样的场景吗?

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

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

希望这可以帮助。

@Portman默认情况下PK == Clustered Index,创建主键约束会自动创建聚集索引,如果不想聚集则需要指定非聚集。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top