重复列以加快查询速度?

Gab*_*mon 34 normalization database-design

标题没有太大意义,但我想不出更好的标题来解决这个问题。

我有以下表格

项目

  • ID
  • 姓名

顾客

  • ID
  • id_project
  • 姓名

付款

  • ID
  • id_customer
  • 日期

当用户进入系统时,他将有权访问某个项目。现在,我想列出该项目的所有付款,这应该很容易:

SELECT FROM payments where id_customer in (SELECT id from customers where id_project = 5)
Run Code Online (Sandbox Code Playgroud)

我的问题是:如果以这种方式向支付表添加一列 id_project 不是更好,那么查询会更容易和更快。

Jef*_*ood 62

您似乎在问非规范化是否有意义。

非规范化是尝试通过添加冗余数据或对数据进行分组来优化数据库读取性能的过程。在某些情况下,非规范化有助于掩盖关系数据库软件固有的低效率。关系规范化数据库对数据的物理存储施加了沉重的访问负载,即使它已针对高性能进行了很好的调整。

答案总是“视情况而定”,所以这是我的经验法则:

如果 ...

  • 数据量不大
  • 你还没有进行大量的连接
  • 和/或数据库性能目前不是瓶颈

然后保持正常化。是的,非规范化速度更快,但这也意味着系统中有冗余数据——必须维护和保持同步的数据。该数据不再有“一个来源”,而是可以偏离的多个来源。随着时间的推移,这是有风险的,所以你不应该这样做,除非你有很好的理由这样做,并得到一些基准的支持。

我只会在...

  • 数据量非常大
  • 连接很昂贵,您必须执行很多操作才能返回甚至是微不足道的查询
  • 数据库性能是瓶颈和/或您希望尽可能快地运行

连接在现代硬件上非常快,但它们从来都不是免费的。


Dav*_*ett 10

您最好将查询重写为:

SELECT payments.*
FROM   customers
JOIN   payments 
ON     payments.id_customer = customers.id
WHERE  customers.id_project = 5
Run Code Online (Sandbox Code Playgroud)

虽然这看起来不那么简洁,一个好的查询规划器会看到你正在尝试做什么并运行你的相关子查询作为上面的连接,一个糟糕的查询规划器最终可能会做一个索引扫描payments.id_customer(假设你有一个相关的索引)(或者更糟的是,表扫描)而不是更有效的方式。如果这个查询的安排包含在更复杂的东西中,即使是一个好的查询计划者也可能看不到优化。将关系表示为连接而不是子查询可能比更改数据结构更重要。

正如杰夫所说,任何非规范化都应该谨慎考虑——它可以带来轻松的性能提升,特别是对于某些报告目的,但由于支持业务逻辑中的错误,可能会导致不一致。

附带说明:显然我不了解你的业务,所以我可能会遗漏一些东西,但你的餐桌关系对我来说似乎很奇怪。它们意味着您永远不能与同一个客户拥有多个项目,这在我的经验中通常是不正确的,至少在很长一段时间内是这样。

customer     project      payment
--------     --------     -------
                          pa_id
             pr_id    <-- payment
cu_id    <-- customer     
Run Code Online (Sandbox Code Playgroud)

或者如果不那么规范化(尽管我怀疑这是否必要):

customer     project      payment
--------     --------     --------
                          pa_id
             pr_id    <-- payment
cu_id    <-- customer 
           `------------- customer    
Run Code Online (Sandbox Code Playgroud)

当然,这仍然降低了与两个客户进行联合项目的可能性......

  • 性能的第一条规则:永远不要在生产中使用 *! (3认同)

小智 6

在某些数据库中,您可以根据复杂的查询创建“物化视图”而不是具有大量数据的复杂视图。这可用于避免历史发展的应用程序系统中的非规范化。如果您决定使用“物化视图”,您必须清楚地了解刷新方法和物化视图将使用的存储量...