数据库设计问题 - 哪个是最好的解决方案?
Posted
技术标签:
【中文标题】数据库设计问题 - 哪个是最好的解决方案?【英文标题】:Database design question - which is the best solution? 【发布时间】:2011-05-12 14:35:08 【问题描述】:我正在使用 Firebird 2.1,我正在寻找解决此问题的最佳方法。
我正在编写一个日历应用程序。不同用户的日历条目存储在一个大日历表中。每个日历条目都可以设置一个提醒 - 只有一个提醒/条目。
从统计上看,随着时间的推移,日历表可能会增长到数十万条记录,而提醒会少得多。
我需要定期查询提醒。
哪个是最好的选择?
A) 将提醒信息存储在日历表中(在这种情况下,我将查询数十万条 IsReminder = 1 的记录)
B) 创建一个单独的 Reminders 表,其中仅包含设置了提醒的日历条目的 ID,然后使用 JOIN 操作查询这两个表(或者可能在它们上创建一个视图)
C) 我可以将所有关于提醒的信息存储在 Reminders 表中,然后只查询这个表。缺点是需要在两个表中复制一些信息,例如为了显示提醒,我需要知道事件的开始时间并将其存储在提醒表中 - 因此我要维护两个具有相同值的表。
你怎么看?
还有一个问题:Calendar 表将包含多个用户的日历,仅由 UserID 字段分隔。由于只能有 4-5 个用户,即使我在这个字段上放了一个索引,它的选择性也会很差——这对于一个有数十万条记录的表来说是不利的。这里有解决方法吗?
谢谢!
【问题讨论】:
【参考方案1】:在选择选项 (A) 时,您应该
在“IsReminder”上提供索引(或 IsReminder、UserId 上的组合索引,只要最适合您的预期查询) 确保您的查询使用此索引如果您为每个要存储的提醒存储多个布尔标志(例如,在事件发生前应通知用户的分钟数),则选项 B 比 A 更可取。但是,您应该猜测在您的程序中您必须多久将两个表连接起来。
如果可以,请避免选项 C。如果您不想对所有三种情况进行基准测试,我建议根据描述的情况从 A 或 B 开始,并且可能您选择的解决方案足够快,所以您不必为其他情况而烦恼。
【讨论】:
Doc,感谢您提供的信息,但您使用的是 Firebird 吗?因为 FB 在索引方面很特别......(见我上面的评论)【参考方案2】:这三种选择各有利弊。最佳选择取决于您未提供的详细信息。一般来说,只要您设置的索引允许正确的检索策略,就不必太担心从十万个条目中选择三个或四个条目。如果不了解索引,无论您做出三个选择中的哪一个,您都可能会遇到麻烦。
如果是我,我会选择 B。我还会将提醒的任何属性存储在提醒表中。
要非常小心您是单独通过 EventId 还是通过 (UserId, EventId) 来识别事件。如果您选择后者,您应该为 Event 表使用复合主键。不要太担心复合主键,尤其是 Firebird。 如果您声明复合主键,请注意声明 (UserId, EventId) 与声明 (EventId, UserId) 的后果不同。它们在逻辑上是等价的,但是两种情况下自动生成的索引的结构会有所不同。
这反过来会影响查询的速度,例如“查找给定用户的所有提醒”。
再一次,如果是我,我会避免选择 C。在架构中引入有害的冗余会带来在更新数据时进行一些非常仔细的编程的责任。否则,您最终可能会得到一个数据库,该数据库将同一事实的相互矛盾的版本存储在数据库的不同位置。
而且,如果您真的想知道对性能的影响,请尝试所有三种方法,加载测试数据,然后进行自己的基准测试。
【讨论】:
感谢详尽的回复 :-) 如果 UserID 不是复合主键的一部分,而是带有索引的简单字段,我想它的选择性会很差,而且检索速度会很差慢? @Steve:发明索引是为了快速查询——如果你有一个带索引的字段,应该可以使用这个索引编写查询。 Doc,我读过 Firebird 索引的选择性是一个重要因素。如果某个字段的索引选择性较低(只有几个不同的值),您可能看不到速度增加...【参考方案3】:我认为您需要创建真实的、虚假的用户数据,并使用您希望运行的一些典型查询来衡量差异。
索引、查询优化和您需要的查询结果类型可以产生很大的不同, 所以在不了解更多信息的情况下很难说出什么是最好的。
【讨论】:
以上是关于数据库设计问题 - 哪个是最好的解决方案?的主要内容,如果未能解决你的问题,请参考以下文章