您如何在数据库模式中表示哈希表集合?

时间:2009-01-16 01:27:55

标签: database database-design list hashtable

如果您尝试在数据库模式中创建域对象,并且在您的代码中,则表示域对象具有哈希表/列表成员,如下所示:

public class SpaceQuadrant : PersistentObject
{

    public SpaceQuadrant()
    {
    }

    public virtual Dictionary<SpaceCoordinate, SpaceObject> Space
    {
        get;
        set;
    }
}

字典只是一个哈希表/列表映射对象键值键,我已经提出了多种方法来创建它,创建各种连接表或加载技术,但它们在获取O方面都很糟糕(1)访问哈希表中的时间。

您如何在数据库模式中表示SpaceQuadrant,SpaceCoordinate和Space Object? 一个简单的架构代码描述会很好, 即

table SpaceQuadrant
{
    ID int not null primary key,
    EntryName varchar(255) not null,
    SpaceQuadrantJoinTableId int not null
                 foreign key references ...anothertable...
}

但是任何想法都会很好,感谢阅读!

更多信息:

感谢你们给出了很好的答案,我只是撇去了他们,我想在回应之前花点时间思考一下。

如果您认为有更好的方法来定义这些课程,那么无论如何都要向我展示一个例子,您喜欢的任何语言都很酷

4 个答案:

答案 0 :(得分:2)

关系不是哈希表;他们是一套。

我不会使用坐标作为关键字来组织数据库。如果对象改变位置怎么办?相反,我可能会将坐标视为对象的属性

此外,我假设有固定数量的维度,例如,三个。如果是这样,那么您可以将对象的这些属性存储在固定列中:

CREATE TABLE SpaceQuadrant (
  quadrant_id INT NOT NULL PRIMARY KEY,
  quadrant_name VARCHAR(20)
  -- other attributes
);

CREATE TABLE SpaceObject (
  object_id INT NOT NULL PRIMARY KEY,
  x NUMERIC(9,2) NOT NULL,
  y NUMERIC(9,2) NOT NULL
  z NUMERIC(9,2) NOT NULL,
  object_name VARCHAR(20) NOT NULL,
  -- other attributes
  quadrant_id INT NOT NULL,
  FOREIGN KEY (quadrant_id) REFERENCES SpaceQuadrant(quadrant_id)
);

在面向对象的类中,不清楚为什么对象在字典中。你提到在O(1)时间访问它们,但为什么你通过坐标来做到这一点?

如果您正在使用它来优化查找某个点附近的对象(例如,玩家的太空船),您还可以构建到您的SQL查询中,该查询会填充此SpaceQuadrant,计算每个对象距该给定点的距离,并按距离对结果进行排序。

我对您的计划了解不足以了解这些建议是否相关。但他们至少会让你想到组织数据的不同方式吗?

答案 1 :(得分:2)

在最简单的情况下,字典有一个键映射到表的主键 - 这样当您指定键的值时,您可以通过简单的查找立即找到匹配的数据。

在这种情况下,您需要一个表SpaceQuadrant,其中包含描述或表征空间象限的任何通用(单值)属性。 SpaceQuadrant表将具有主键,可能是生成的ID,可能是自然值。然后,散列表将包含一个表,其中主键值用于交叉引用SpaceQuadrant,其中包含位置(SpaceCoordinate)以及象限和坐标的属性。

现在,如果您有可扩展的DBMS,则可以为SpaceCoordinate定义用户定义的类型;如果不这样做,你可以使用三个列 - 例如x,y,z或r,theta,rho--来表示位置(SpaceCoordinate)。

总的来说,我所描述的结构与Bill Karwin非常相似;关键(在我重读信息之前没有意图)不同之处在于,如果您确定这是最好的组织方式,那么在我的书中完全可以将该位置作为子坐标表主键的一部分。它。您可能还有一个对象ID列,它是备用候选键。或者,如果对象具有独立于空间象限的存在,它们恰好位于当前(或者可以存在于多个位置 - 因为它们不是点而是空间站或某些东西),那么您可能拥有空间对象单独的表。什么是最好的取决于我们没有的信息。

您应该了解使用SpaceCoordinate作为主键的一部分的限制:

  • 没有两个对象可以占据相同的位置(在散列表中以及在3D空间中称为碰撞),
  • 如果位置发生变化,则必须更新密钥数据,这比更新非密钥数据更贵,
  • 接近查找很难 - 精确查找很容易。

你的字典在记忆中也是如此;如果更改坐标,则必须从旧位置删除记录并将其放在字典中的新位置(或者语言必须在幕后为您执行此操作)。

答案 2 :(得分:2)

字典表。哈希是一个使用何种索引的问题。大多数RDBMS都假设表格大且密集,使得散列索引不合适。

table SpaceQuadrant { 
    ID Primary Key,
    -- whatever other attributes are relevant
}

table Space {
    SpaceCoordinate Primary Key,
    Quadrant Foreign Key SpaceQuadrant(ID),
    SpaceObject -- whatever the object is
}

您的Space对象具有对它们所在的象限的FK引用。

根据您的RDBMS,您可能能够找到一个基于哈希的索引,可以获得您希望的性能。例如MySQL,使用HEAP存储引擎支持HASH索引。

答案 3 :(得分:1)

首先,许多数据库中都存在对地理位置数据的专用支持 - 可以使用不同的算法(例如,存在B树的空间版本),并且可能存在对邻近搜索的支持。

由于每个SpaceQuadrant都有一个不同的哈希表,你需要类似的东西(从S.Lott的帖子编辑):

table Space {
    SpaceCoordinate,
    Quadrant Foreign Key SpaceQuadrant(ID),
    SpaceObject -- whatever the object is (by ID)
    Primary Key(SpaceCoordinate, Quadrant)
}

这是(SpaceCoordinate, Quadrant) -> SpaceObjectId词典。

=====

现在,关于你的O(1)性能问题,有很多原因导致它被错误地解决。

正如有人告诉你的那样,你可以在许多DB中使用基于内存的表的哈希索引。但是如果你需要持久存储,你需要更新两个表(内存一个和持久存储)而不是一个(如果没有内置的支持)。要发现这是否值得,您需要对实际数据(实际数据大小)进行基准测试。

此外,强制将表放入内存可能会产生更糟糕的影响。

如果某些东西被交换了,那么你已经死了 - 如果你使用过B-Tree(即普通的基于磁盘的索引),它的算法会最小化所需的I / O.否则,所有DBMS都将使用哈希表并依赖于交换,而不是B-Trees。你可以试着预测你是否适合记忆,但是......

此外,B-Trees不是O(1)但是它们是O(log_512(N)),或类似的东西(我知道崩溃到O(log N),但请耐心等待)。你需要(2 ^ 9)^ 4 = 2 ^ 36 = 64GiB为4,如果你有这么多的数据,你需要一个大的铁服务器,以适应内存。所以,它几乎是O(1),而常数因素实际上是重要的 曾经听说过低渐近复杂度,大常数因子算法,这些算法比不简单的数据大小更简单吗?

最后,我认为数据库作者比我和你聪明。特别是考虑到SQL的声明性,以这种方式手动优化它不会付出代价。如果索引适合内存,我猜他们可以根据需要选择构建和使用磁盘索引的哈希表版本,如果值得的话。调查你的文档。

但最重要的是,过早的优化是邪恶的,特别是当它属于这种类型时(我们自己在考虑奇怪的优化,而不是标准的SQL优化),并且使用声明性语言。