5

我们正在设计一个典型的 OLTP 应用程序(想想:采购系统)。然而,这个特别需要一些用户离线,所以他们需要能够将数据库下载到他们的机器上,在它上面工作,然后一旦他们在 LAN 上同步回来。

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

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

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

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

谢谢!
丹尼尔

4

15 回答 15

8

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

您必须关心的是人类可读的标识符。指南不能由人交换 - 如果它是指南,您能想象通过电话确认您的订单号吗?所以在离线场景中,您可能仍然需要生成一些东西——比如发布者(工作站/用户)ID 和一些序列号,所以订单号可能是 123-5678 -。

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

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

于 2008-09-02T18:56:50.063 回答
3

@SqlMenace

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

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

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

于 2008-09-03T02:14:23.600 回答
2

这是对 GUID 的完美使用。唯一的缺点是在 INT 上使用 GUID 时会稍微复杂一些,并且大小差异很小(16 字节对 4 字节)。

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

于 2008-09-02T18:41:55.297 回答
1

通过 GUID 键访问这些表会很慢吗?

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

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

于 2008-09-02T18:54:46.963 回答
1

你说得对,这是一个老问题,它有两个典型的解决方案:

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

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

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

于 2008-09-03T02:21:22.943 回答
1

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

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

于 2008-09-03T02:25:53.247 回答
1

我只想向您指出顺序 Guid 相对于标准 Guid 的性能改进是什么?,其中涵盖了 GUID 谈话。

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

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

于 2009-08-19T16:52:40.460 回答
0

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

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

于 2008-09-02T18:41:09.197 回答
0

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

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

于 2008-09-02T18:47:31.990 回答
0

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

于 2008-09-02T18:48:23.907 回答
0

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

于 2008-09-02T18:51:23.167 回答
0

@西蒙,

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

于 2008-09-02T19:54:19.613 回答
0

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

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

它专门设计用于

现场部队应用 (FFA)。FFA 通常具有以下一项或多项属性

它们允许用户在与后端网络断开连接的情况下执行他们的工作职能——在客户位置现场、在路上、在机场或在家中。

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

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

于 2008-09-02T20:01:57.863 回答
0

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

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

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

希望这可以帮助。

于 2008-09-02T20:06:43.047 回答
0

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

于 2008-09-03T02:24:41.313 回答