9

一段时间以来,我一直试图很好地掌握 Azure 表存储,虽然我大致了解它的工作原理,但我真的很难动摇我的关系数据库思维。我通常通过例子学得最好,所以我想知道是否有人可以帮助我。我将概述如何使用关系数据库解决问题的简单设置,有人可以帮助指导我将其转换为使用 Azure 表存储吗?

假设我有一个简单的笔记应用程序,它有用户,每个用户可以拥有任意数量的笔记,每个笔记可以拥有任意数量的用户(所有者或查看者)。如果我要使用关系数据库部署它,我可能会按如下方式部署它:

对于数据库,我将从以下内容开始:

CREATE TABLE [dbo].[Users](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [Username] [nvarchar](20) NOT NULL)

CREATE TABLE [dbo].[UsersNotes](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [UserID] [int] NOT NULL,
    [NoteID] [int] NOT NULL)

CREATE TABLE [dbo].[Notes](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [NoteData] [nvarchar](max) NULL)        

Users.ID and UsersNotes.UserID然后,我将在约束之间以及约束之间建立关系Notes.ID and UsersNotes.NoteID以强制执行参照完整性。

对于应用程序,我会让 ORM 为每个实体生成一些具有匹配名称属性的实体,我可能会称之为一天:

public class Users
{
    public int ID { get; set; }
    public String Username { get; set; }
}
// and so on and so forth

我意识到这种设计完全依赖于关系数据库,我正在寻找一些关于如何改变这种思路以使用 Azure 表存储或任何其他非关系数据存储技术的建议。

让我们也假设我已经安装了 Azure SDK,并且已经使用它,但是我使用 SDK 的工作知识是有限的,我宁愿不专注于那个,而是一个好的解决方案到上面的样子。一个好的起点将有助于使 SDK 对我有意义,因为我将有一个参考点。

为了完整起见,让我们说

  • 笔记数据在首次创建时会频繁更改,并随着时间的推移逐渐减少
  • 用户会有很多笔记,笔记可能有多个用户(不是并发的,只是查看者)
  • 我预计用户数量很少(低数百),但我希望有相当数量的笔记(每用户低数百)
  • 我希望查询Username最多,然后显示用户可以访问的注释
  • 我还希望在查看便笺时,向其他有权访问该便笺的用户显示反向查找
4

3 回答 3

5

您可以将 Azure 表视为对象的集合。

在 Azure Table 中,对象是一个实体。

要使用您的示例,用户将从 TableStorageEntity 派生。

Azure 表存储不是关系型的。没有连接。但是有 LINQ,一种支持多种语言的查询语言。因此系统不提供连接操作和参照完整性。开发人员必须这样做。

一些显着的优势:

(1) Azure 表自动跨多个存储节点扩展以保持性能,即使您正在处理数十亿个实体。(2) 它们被复制 3 次 (3) 它们带有 SLA (4) 表服务 API 与 REST API 兼容,因此可以从非 Microsoft 技术访问它们。

若要允许将对象存储在 Azure 表中,只需从 TableStorageEntity 派生。

如果您搜索“Microsoft Azure 表虚拟实验室”,可以找到更多信息。

下面的代码片段忽略了 (1) 分区键 (2) 行键。但这是你需要担心的事情。将这两个键视为关系表上的主键。

您需要非常仔细地考虑这两个关键。它们决定性能。因为您只获得一组密钥,您可能需要保留数据的非规范化副本以获得最佳性能。

    公共类用户:TableStorageEntity
    {
        公共 int ID { 获取;放; }
        公共字符串用户名 { 获取;放; }
    }

看看手上的。Azure 表便宜且易于使用。

于 2012-08-01T22:10:08.687 回答
5

一些想法...

  1. 从整体上考虑不同的实体,并避免使用任何规范化技术进一步分解它们。
  2. 为每个实体提供一个标识符,如果对其进行索引,将允许精确键搜索和范围键搜索匹配。
  3. 将标识符拆分为 2 个段以满足 Azure 表存储可扩展性需求。如何很好地分割,它本身是一个单独的主题,但通常在定义明确的自然段中分割效果很好。

在您的示例中,这两个实体是 User 和 Note。

UserId 足以唯一标识用户。对用户的范围搜索可能并没有真正有用。用户 id 在这里可以是任何固定长度的值。

UserId + NoteId 足以唯一标识一条笔记。note id 可能类似于日期/时间戳 + 用于唯一性的 GUID。这样的键与 UserId 结合将唯一地标识笔记,并允许在给定时间段内对所有用户的笔记或用户的笔记进行范围搜索。

所以如果 UserId = “ABCD”,NoteId 可能是 “20120801-00f64829-6044-4fbb-8b4e-ae82ae15096e”。

您可以将两个实体存储在相同或不同的表中。这里有一些不同的方法……</p>

如果每个实体都有自己的表,

  • 对于用户,分区键可以是“ABCD”,而行键实际上可以是任何东西,您只搜索分区键。

  • 或者分区键可以是“AB”,行键可以是“CD”。

    以上两种方法都可以很好地适应大量用户。

  • 或者分区键可以是“*”,行键可以是“ABCD”。这对于较小的用户集非常有效,您可以将用户和注释放在同一个表中。

备注

  • 分区键可以是“ABCD”,行键可以是“20120801-00f64829-6044-4fbb-8b4e-ae82ae15096e”</p>

  • 这里的范围搜索可能是

    • 在 PartitionKey = “ABCD” 上获取用户的所有笔记。
    • 在 PartitionKey = “ABCD” 和 RowKey >=“20120801” 和 RowKey <= “20120901” 上获取日期范围内的笔记。

更新

我误读了您的问题,并假设用户和笔记之间只有一对多的关系。由于存在多对多关系,因此需要 4 个实体来建模,除非您不介意重复。(如果注释很短且不可变,则它们可以复制,您不必对连接进行建模)。

如果键在不同的键范围内并且可以轻松区分,则可以将多个实体放在单个表中。尽管在实践中这并不常见,除非有特殊需要,通常是事务性写入到同一分区(不适用)。

所以单个表模式可能看起来像这样。对于多个表,可以删除分区键前缀。

  • 您还可以在 3 个表中对此进行建模,一张用于 User,一张用于 Notes,一张用于双向关系。
  • 您也可以部分在 SQL 中建模,部分在 Azure 存储中建模。Blob 或表中的注释和用户数据以及 SQL 中的关系。

.

Entity        Partition Key              Row Key            
User          “U” + UserId      
Note          “N” + NoteId(Date)         NodeId(GUID)
User Note     “X“  + UserId              NoteId(Date+GUID)
Note User     “Y“  + NoteId(Date+GUID)   UserId    

这些是一些替代方案,您需要确定哪些最适合您的数据和您的需求。

另一个更新
实际上 3 个实体对于 UserNote 实体中的 Note 就足够了。

如果 UserId = GUID
并且 NoteId = Date+GUID

Entity      Partition Key  Row Key             Note  User           
User        UserId      
User Note   UserId         NoteId(Date+GUID)   Note          (Contains Note and can query for all notes for a user).
Note User   NoteId(Date)   NodeId(GUID)              UserId  (Can query for all Users of a note. Join on ‘User Note’ to get note.)  
于 2012-08-02T06:10:21.887 回答
1

为什么UsersNotes 有一个ID?为什么不只把 UserID、NoteID 作为复合主键呢?

所以三个表,每个表有 2 个属性。第一个是 PartitionKey,第二个是 RowKey。

如果您希望在 NoteID 上查询大量用户 ID,那么在 PartitionKey 上搜索第四个表比在 RowKey 上搜索要快。而且它通常会更便宜,因为它会导致更少的交易。但是你有事务来加载表。

public class NotesUsers : TableStorageEntity
    {
        public int NoteID { get; set; }
        public int UserID { get; set; }
    }

对于用户表,如果这是常见的查询条件,则使用 UserName 作为 PartitionKey。

ATS 中没有声明性引用完整性。您将需要在应用程序中强制执行所有数据关系。两部分复合键。对 RowKey 的搜索就像扫描(而不是搜索)。对 PartitionKey 的搜索就像搜索一样。

但我会使用 SQL。如果笔记是某人打字,那么这是一个相对较少的数据量。它是关系数据。

于 2012-08-02T13:27:33.023 回答