Android:在 SQLite 中使用 UUID 作为主键

Posted

技术标签:

【中文标题】Android:在 SQLite 中使用 UUID 作为主键【英文标题】:Android: Use UUID as primary key in SQLite 【发布时间】:2012-12-20 12:39:59 【问题描述】:

我的应用需要与其他应用用户同步(在自己的设备上)。我还想支持离线编辑,当用户连接到互联网时,它会同步到其他协作用户。

因此,用户 A 更改(当他离线时)一些数据(换句话说,他会更新数据库条目)或向数据库添加新记录。当用户 A 连接到 Internet 时,所有更改和新记录都会传递给其他协作用户。因此用户 B 将获得更改/更新,并可以将它们插入/更新到用户 B 的本地设备数据库中。

但我需要确保数据库条目的 ID 在整个系统中是唯一的。因此我需要使用 UUID 之类的东西。

我的问题:在 android sqlite 数据库表中使用 UUID (String / Varchar) 作为主键而不是自动递增的整数是不是一个坏主意?

我猜使用字符串(UUID 有 36 个字符)作为主键会出现性能问题。

我猜索引 uuids 而不是整数需要更长的时间(比较字符串与比较整数)。我还猜想,当我使用 UUID 时,每次插入新的数据库记录/条目时,数据库都需要重新索引主键列,因为它们的主键索引不再按排序顺序(这将是我使用整数自增主键,因为以后的每条记录都加在最后,因为新的自增主键始终是目前为止最大的数,所以索引会自动排序)。我还需要做的是加入 2 - 3 张桌子。我还猜想在 JOINS 上比较字符串而不是整数会减慢数据库查询速度。

但是我看不出有任何其他可能实现这样的协作同步系统,所以我必须使用 UUID,对吧?

另一种可能性是使用整数自增主键并使用第二列 uuid。因此,要在用户本地设备上工作,我会将此主键(整数)用于 JOINS 等,而我会使用 uuid 列与其他用户同步。

你们如何看待这种方法,或者在您看来它是否需要大量工作,因为您不会期望直接使用 UUID 作为主键会出现重大的性能问题?

还有其他建议吗?

【问题讨论】:

这是一篇旧帖子,但我想我会分享一个我已经实施的方法。我为设备应用程序实例生成一个 UUID 并将其存储在共享首选项中。我在 Room 表(Int 或 Long)中使用了一个简单的自动生成键。在向服务器发送数据时的 API 中,我在标头中包含应用程序实例 UUID。在此模型中,服务器可以区分和处理服务器表键的分配,该键会同步回设备。出于跨平台的原因,我选择了 UUID 而不是 FID。显然有很多方法可以给猫剥皮。 【参考方案1】:

在 android sqlite 数据库表中使用 UUID (String / Varchar) 作为主键而不是自动递增的整数是不是一个坏主意?

我能想到的唯一确定的问题是您将无法使用CursorAdapter 及其子类来显示对该表的查询结果。 CursorAdapter 需要 Cursor 中的唯一整数 _id 列,并且您可能没有其中之一。您必须创建自己的适配器,可能扩展 BaseAdapter 来处理它。

我猜使用字符串(UUID 有 36 个字符)作为主键会出现性能问题。

可能,但如果它变成设备大小的数据库的重大问题,我会有些惊讶。

但是我看不出有任何其他可能实现这样的协作同步系统,所以我必须使用 UUID,对吧?

您的网络协议需要某种 UUID。据推测,您的数据库中将需要该 UUID。该 UUID 是否需要成为表的主键,我不能说,因为我不知道您的架构。

另一种可能性是使用整数自增主键并使用第二列 uuid。因此,要在用户本地设备上工作,我会将此主键(整数)用于 JOINS 等,而我会使用 uuid 列与其他用户同步。

正确。您将拥有一个 UUID->local 整数 ID 映射表,在网络协议中使用 UUID,并主要使用本地整数 ID 保留本地数据库。这是否会显着提高性能(特别是考虑到数据库架构复杂性的增加),我不能说。

你们如何看待这种方法,或者在您看来它是否需要大量工作,因为您不会期望直接使用 UUID 作为主键会出现重大的性能问题?

恕我直言,要么运行一些性能测试,以便获得一些具体的可比数据,要么只在您的数据库 I/O 看起来缓慢时才担心它。

【讨论】:

您可以将 UUID 存储为 16 字节二进制文件 @EirNym:很高兴知道这一点,尽管我看不出它与问题、答案或您对我的答案的明显反对票有什么关系。 您告诉我们 ASCII 表示只是 SQLite3 中 UUID 的一种,并说明了它的缺点。二进制表示没有这样的缺点:它对于搭载 Android 2.3+ 的设备来说已经足够快了,这在 2013 年被推荐为最低要求。今天我们有更快的设备,我们不仅可以使用 SQLite3 作为数据库引擎,而且它仍然很常见。 @EirNym:“您说 ASCII 表示只是 SQLite3 中 UUID 的一种,并说明了它的缺点”——我的答案中没有任何符合您描述的内容。例如,术语“ASCII”仅出现在您的评论和此回复评论中。答案集中在CursorAdapter 要求的问题上,您的解决方案也没有解决。 这是BLOB-like 类型,您必须使用文本表示进行直接值比较,但它足够快用作主键/外键。是的,您可以使用varchar 主键,但您可以解释使用二进制表示可以减少缺点。 Android 的代码不会改变。【参考方案2】:

可以在一些相关的 UUID/SQLite 问题中找到作为二进制和文本的 UUID 的一组性能结果:https://***.com/a/11337522/3103448

根据结果,二进制和字符串 UUID 在 SQLite 中都可以在索引时高效地创建和查询。一个单独的权衡是人类可读的字符串是否更适合二进制文件大小的较小数据大小。

【讨论】:

以上是关于Android:在 SQLite 中使用 UUID 作为主键的主要内容,如果未能解决你的问题,请参考以下文章

SQLite - 在 SELECT INTO 语句上生成 GUID/UUID

如何在 SQLAlchemy 中使用 UUID?

为啥 BLE 服务 UUid 在 android 和 iphone 中不同?

使用带有 Android 的 Room 使用 UUID 作为主键

使用 android UUID 查找设备位置

我们可以在 Sqlite 数据库中使用 Guid 作为主键吗