重复列以加快查询速度?


30

标题没有太大意义,但我想这个问题的标题更好。

我有下表

专案

  • ID
  • 名称

顾客

  • ID
  • id_project
  • 名称

付款方式

  • ID
  • id_customer
  • 日期

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

SELECT FROM payments where id_customer in (SELECT id from customers where id_project = 5)

我的问题是:用这种方式向付款表添加id_project列是否更好,这将使查询更容易,更快捷。


1
因此查询对于现代RDBMS(不是更好,请使用join)不是问题。
加里克2011年

4
同意,获取有关subselect vs join的查询计划,然后看看哪个更好
Gaius

1
我认为这篇SO帖子值得一看,因为@igor提到使用JOIN或IN
CoderHawk 2011年

Answers:


52

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

非规范化是尝试通过添加冗余数据或对数据进行分组来优化数据库的读取性能的过程。在某些情况下,非规范化有助于弥补关系数据库软件固有的效率低下的问题。关系规范化数据库对数据的物理存储施加了沉重的访问负载,即使对其进行了适当的调整以提高性能也是如此。

答案总是“取决于”,这是我的经验法则:

如果...

  • 数据量不大
  • 你已经没有做大量的联接
  • 和/或数据库性能当前不是瓶颈

然后保持正常状态。是的,非规范化速度更快,但这也意味着系统中存在冗余数据,这些数据必须维护并保持同步。该数据不再有“一个源”,而是可以偏离的多个源。随着时间的流逝,这是有风险的,因此,除非有充分的理由并有一些基准支持,否则您不应该这样做。

我只会在...

  • 数据量非常大
  • 联接很昂贵,您必须执行很多次才能返回甚至是琐碎的查询
  • 数据库性能是一个瓶颈,并且/或者您希望尽快运行

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


9

您最好将查询重写为:

SELECT payments.*
FROM   customers
JOIN   payments 
ON     payments.id_customer = customers.id
WHERE  customers.id_project = 5

尽管这看起来不太简洁,但是好的查询计划者会看到您尝试执行的操作并通过上述联接运行关联的子查询,但是糟糕的查询计划者可能最终会进行索引扫描payments.id_customer(假设您有相关的索引) )(或更糟糕的是,表扫描)而不是更有效的方式处理事务。如果此查询的安排包含在更复杂的内容中,则即使是优秀的查询计划者也可能看不到优化。将关系表示为联接而不是子查询可能比更改数据结构有更多不同。

正如Jeff所说,任何非规范化都应谨慎考虑-可以轻松地提高性能,特别是出于某些报告目的,但由于支持业务逻辑中的错误,可能导致不一致。

附带说明:显然我不了解您的业务,因此我可能会丢失一些东西,但是您的表关系对我来说似乎很奇怪。它们暗示您不能与同一客户有多个项目,至少在很长一段时间内,根据我的经验,这通常是不正确的。

customer     project      payment
--------     --------     -------
                          pa_id
             pr_id    <-- payment
cu_id    <-- customer     

或标准化程度较低(尽管我怀疑那是必要的):

customer     project      payment
--------     --------     --------
                          pa_id
             pr_id    <-- payment
cu_id    <-- customer 
           `------------- customer    

当然,这仍然打折了与两个客户进行联合项目的可能性。


3
性能的第一原则:切勿在生产中使用*!
2011年

@布莱恩:非常有效的一点。并且,如果sys.depends由于使用DROP VIEW+ CREATE VIEW代替了而无法退出,那么在select子句中避免*以及潜在的性能隐患也可以避免MSSQL视图中的列排序问题ALTER VIEW
David Spillett

@Brian我写了*以便于写作。
加布里埃尔·所罗门

该项目更像是具有其域上的独立应用程序,并且属于不同的客户,因此客户不能在不同的项目上拥有相同的帐户
Gabriel Solomon

4

在某些数据库中,您可以根据复杂的查询来创建“材料化视图”,而不是使用包含大量数据的复杂VIEWS。这可以用来避免在历史悠久的应用程序系统中进行非规范化。如果您决定使用“物化视图”,您必须对刷新方法和物化视图将使用的存储量有个清晰的了解...

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.