数据库表优化连接与重复列

时间:2010-09-27 17:58:27

标签: sql database-design query-optimization

这更像是一种偏好,但我想知道人们认为什么是最佳选择。我有一个问题,答案和点(因为我需要跟踪哪个用户指出了这一点)

表转储

Question:
  id
  title

Answer:
  id
  question_id
  user_id
  response

Point_Answer:
  id
  answer_id
  user_id
  points

因此,在此布局中获取Top Answer将需要复杂的连接序列。

SELECT t2.id, t2.user_id, t2.response, MAX(points)
FROM Question as t1,
  (SELECT qa.*, SUM(pa.points) as points
  FROM answer as qa, Point_Answer as pa
  WHERE qa.id = pa.answer_id
  GROUP BY qa.id) as t2
WHERE t1.id = %s AND t1.id = t2.question_id

如果我这样改变它的地方:

Question:
  id
  title

Answer:
  id
  question_id
  user_id
  response
  points

Point_Answer:
  id
  answer_id
  user_id
  points

查询将减少负担

SELECT A.id, A.user_id, A.response, MAX(points)
FROM Question as Q, Answer as A
WHERE Q.id = %s AND Q.id = A.question_id
GROUP BY A.id

也意味着我必须确保添加Point_Answer时添加Answer.points。所以基本上是一个额外的更新。基本上它是“完整性与冗余”和一些优化,更好的方法是什么?

3 个答案:

答案 0 :(得分:5)

这取决于第一个不是连接的复杂性有多慢。完全这样做是一个非常糟糕的主意,因为你不想写(一次)更复杂的查询。表现是做这种性质的唯一真正原因。

如果第一个是慢得令人无法接受的话,那么对这些点求和的表或字段可以是可接受的非规范化,只要你通过触发器而不是从应用程序保持字段更新(唯一的方法是确保非规范化数字的准确性) )。您需要测试解决方案,包括额外的更新时间,以确定您是否确实节省了任何处理时间。这可能取决于数字的更改频率。如果你在更新时添加一秒并在select上保存十秒,那么实例,但每个selct你有10,000次更新,这不是一个好的优化。但是,如果您将报告从一小时到几毫秒,并且只在插入或更新中添加毫秒,则可能是可接受的。

如果没有实际编码和测试具有生产级工作负载和数据的解决方案,就无法回答这个问题。

答案 1 :(得分:2)

这取决于很多因素,其中大多数因素取决于您的设置。

两个最重要的因素是:

  • 您运行查询的频率。请记住,第二种解决方案不仅使用更多磁盘空间(理论上可能会降低性能),还需要在添加记录时处理非规范化结构。虽然可以使用触发器自动执行(取决于RDBMS),但它仍然是性能开销。
  • 您正在使用的RDBMS。你的第一个查询可能很丑陋(我看到更糟糕的是),但你确定它很慢吗?获得该问题的明确答案的唯一方法是运行查询并使用EXPLAIN [query]检查您的RDBMS使用了什么查询计划。

基本上,我会坚持第一个解决方案。没有规范化的关系方案有时是一件好事,但你应该对结构进行非规范化处理,如果你确定的话,它会给你带来性能提升,如果你已经在生产环境中发现应用程序的瓶颈。

答案 2 :(得分:1)

如果查询表现得相当好,我会保持原样。在我的书中,一个丑陋,表现良好的查询超过了冗余。

使用冗余选项,您需要确保将更新语句封装在事务中以确保所有内容都得到更新;否则,您将面临使数据不同步的风险。

我使用了一些遗留应用程序,这些应用程序在没有事务的情况下进行了冗余路由,当一个表因任何原因没有得到更新时,它会变得混乱。