草庐IT

mysql - 在数据库中,什么时候应该存储派生数据?

coder 2023-06-12 原文

我的问题是关于非规范化。在数据库中,何时应该将派生数据存储在自己的列中,而不是每次需要时都计算?

例如,假设您的用户因其问题而获得支持。您在其个人资料上显示用户的声誉。当用户被点赞时,您应该增加他们的声誉,还是应该在检索他们的个人资料时计算它:

SELECT User.id, COUNT(*) AS reputation FROM User
LEFT JOIN Question
  ON Question.User_id = User.id
LEFT JOIN Upvote
  ON Upvote.Question_id = Question.id
GROUP BY User.id

获取用户声誉的查询必须占用多少处理器,才值得使用自己的列增量跟踪它?

继续我们的示例,假设 Upvote 的权重取决于投它的用户拥有多少 Upvote(而不是声誉)。检索他们的声誉的查询突然爆炸:

SELECT
  User.id AS User_id,
  SUM(UpvoteWeight.weight) AS reputation
FROM User
LEFT JOIN Question
  ON User.id = Question.User_id
LEFT JOIN (
  SELECT
    Upvote.Question_id,
    COUNT(Upvote2.id)+1 AS weight
  FROM Upvote
  LEFT JOIN User
    ON Upvote.User_id = User.id
  LEFT JOIN Question
    ON User.id = Question.User_id
  LEFT JOIN Upvote AS Upvote2
    ON
      Question.id = Upvote2.Question_id
      AND Upvote2.date < Upvote.date
  GROUP BY Upvote.id
) AS UpvoteWeight ON Question.id = UpvoteWeight.Question_id
GROUP BY User.id

这与增量解决方案的难度相去甚远。规范化何时值得,规范化的好处何时会失去非规范化的好处(在这种情况下是查询难度和/或性能)?

最佳答案

How processor intensive does the query to get a User's reputation have to be before it would be worthwhile to keep track of it incrementally with its own column?

这里确实有两个问题:(1) 此更改是否会提高性能以及 (2) 性能改进是否值得付出努力?


至于性能有无提升,这基本上是一个标准的利弊分析。

归一化的好处基本上有两方面:

  • 更轻松的数据完整性

  • 重新计算没有问题(例如,如果基础数据发生变化,派生列需要重新计算)。

如果您使用稳健实现的解决方案(例如触发器、Sstored-proc-only 数据更改以及已撤销的直接表更改权限等)来覆盖数据完整性,那么这将直接计算验证成本是否源数据更改是否保证派生数据重新计算与每次都重新计算派生数据。 (注意:保持数据完整性的另一种方法是强制按计划重新计算派生数据,其中数据可以承受一些时间容差的不准确。StackExchange 的一些数字采用了这种方法)。

在一个典型的场景中(更多的数据检索和更少的基础数据更改)数学很明显倾向于在表中保留非规范化的派生数据。

在极少数情况下,基础数据经常更改,但派生数据却没有那么频繁地检索,这样做可能是有害的。


现在,我们要解决更重要的问题:性能改进是否值得付出努力?

请注意,与所有优化一样,最大的问题是“优化是否值得?”,因此主要考虑两个方面:

  1. 测量准确的性能差异和一般分析。

  2. 此特定优化在系统全局中的上下文。

例如如果查询性能的差异——在优化时必须首先测量——缓存的派生数据和计算的数据之间的差异为 2%,那么实现信誉缓存列的额外系统复杂性可能不值得首先。但是,就边际改进而言,关心与不关心的阈值取决于您应用程序的总体情况。如果您可以采取措施在不同的地方将查询性能提高 10%,那么专注于此,而不是 2%。如果您是 Google,额外 2% 的查询性能需要 20 亿美元的额外硬件成本来承担,那么无论如何都需要对其进行优化。

关于mysql - 在数据库中,什么时候应该存储派生数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4127075/

有关mysql - 在数据库中,什么时候应该存储派生数据?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  3. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  4. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  5. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  6. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  7. ruby - ruby 中的 TOPLEVEL_BINDING 是什么? - 2

    它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput

  8. ruby - Infinity 和 NaN 的类型是什么? - 2

    我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

  9. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  10. ruby - 为什么 SecureRandom.uuid 创建一个唯一的字符串? - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?

随机推荐