【问题标题】:Should relational tables contain duplicate data to speed up queries关系表是否应包含重复数据以加快查询速度
【发布时间】:2012-12-28 10:57:47
【问题描述】:

我有一个包含 4 个表的 MySQL 数据库:

job
job_application
client
candidate

每个表都有自己的主键,即job_idjob_application_idclient_idcandidate_id

client 表中的雇主可以在job 表中发布职位。 job 表包含一个标识客户端的client_id 字段

candidate 表中的候选人可以申请工作,在job_application 表中插入一行。 job_application 表包含一个 job_id 字段和一个 candidate_id 字段,用于标识工作是什么以及谁申请了它

我在为雇主编写查询以管理他们收到的工作申请时遇到了一些问题。举个例子,我写的一个函数从job_application中删除行

public function deleteJobApplications($job_application_ids) {
    $this->db->query("DELETE ja.* FROM " . DB_PREFIX . "job_application ja LEFT JOIN " . DB_PREFIX . "job j ON (j.job_id = ja.job_id) WHERE ja.job_application_id IN ('" . implode("','", array_map('intval', $job_application_ids)) . "') AND j.client_id = '" . (int)$this->client->getClientId() . "'");
}

因为client_id 只在job 表中被引用,所以每次我想从job_application 表中UPDATEDELETE 时,我都需要LEFT JOIN job

我应该在job_application 表中添加另一个client_id 字段,本质上是复制数据库中已经保存的数据,还是继续为每个UPDATEDELETE 使用LEFT JOIN

【问题讨论】:

  • 为了速度和复杂性最小化而拥有冗余数据对数据库来说并不陌生,关键是平衡
  • 我想说复制外键是提高数据库性能的正确做法,你必须确保表保持一致。尝试一些性能测试(大量数据集),看看它是否对您有很大帮助
  • 我认为你应该检查 indexex,做一些“解释”,我确实在一个像样的服务器上在不到一毫秒的时间内离开了具有 +100m 行的表(平均约为 4ms) ,不是高科技。我不认为你有那么多行,左连接应该可以正常工作。
  • Cross referenced table 是包含外键的典型案例。索引可以使一个巨大的表更快。所以你可以检查那些。 +1 拉杜
  • 我不确定您在这里要做什么,但应该由jobID.. 删除作业。客户端可以删除或更新作业,job_application 表应该处理@987654352 @ 该特定请求。有什么特殊原因不能使用jobID

标签: mysql database-design indexing database-performance


【解决方案1】:

您的问题不是您需要通过引入“client_id”作为冗余列来非规范化“job_applications”。 (目前接受的答案在这方面实际上是不正确的。)您的问题是您一开始没有正确规范化。如果您,那么“client_id”列将已经在该表中,并且您的问题一开始就不会出现。

让我们假设候选人姓名、客户姓名和职位名称是全球唯一的。

一个看起来像这样的表将满足名为“candidate_name”的人在“client_name”公司申请“job_name”的谓词。

job_applicatons
Person named <candidate_name> applies for <job_name> at company <client_name>.

client_name  job_name                candidate_name  
--
Microsoft    C++ programmer, Excel   Ed Wood 
Microsoft    C++ programmer, Excel   Dane Crute 
Microsoft    C++ programmer, Excel   Vim Winder
Microsoft    C++ programmer, Word    Wil Krug
Microsoft    C++ programmer, Word    Val Stein
Google       Python coder, search    Ed Wood
Google       Programmer, compilers   Ed Wood
Google       Programmer, compilers   Val Stein

三列,没有 id 号,没有空值,没有非主属性,都是键。这种关系在 6NF 中。

很明显,您可以通过从前两列中选择不同的值来为工作(或工作机会)创建一个表。外键引用很明显。

jobs
Company named <client_name> offers <job_name>.

client_name  job_name
--
Microsoft    C++ programmer, Excel
Microsoft    C++ programmer, Word
Google       Python coder, search
Google       Programmer, compilers

以类似的方式,您可以为一组公司仅从第一列中选​​择不同的值,为一组申请人仅从最后一列中选择不同的值。同样,外键引用应该是显而易见的。

clients
Company named <client_name> is a client.

client_name
--
Microsoft
Google

candidates
Person named <candidate_name> is looking for a job.

candidate_name  
--
Ed Wood 
Dane Crute 
Vim Winder
Wil Krug
Val Stein

所有这些表都在 6NF 中。

使用代理键和自然键来扩充表不会改变正常形式,前提是您正确执行此操作。让我们用您的代理 ID 号替换“job_applications”中的自然键。进行替换将使您的表格看起来像这样。 (实际上,您也会在其他表中执行相同的操作。)

job_applications
--
client_id
job_id
candidate_id
primary key (client_id, job_id, candidate_id)
other columns go here...

请注意,client_id 已经存在。如果没有其他列,则您至少仍处于 5NF 中。

【讨论】:

  • 感谢您为此付出的时间和精力,但它没有回答我是否应该在 job_application 表中添加另一个 client_id 以提高 UPDATE 和 DELETE 的性能?
  • 如果您从一开始就将表标准化为 5NF,那么它就已经存在了。请参阅上面的表格“job_applications”。
  • 好吧...虽然仍然没有真正回答我原来的问题。还是谢谢
  • 您的原始问题(以及您接受的答案)基于对规范化的错误理解。为了更清楚,我更新了我的答案。
  • 优秀。更新的答案非常有帮助,谢谢。我已将接受的答案更改为这个
【解决方案2】:

要回答您的问题,这取决于您的情况,尤其是桌子的大小是否值得。 这个过程称为非规范化。 例如,您可以在此处获取信息: http://en.wikipedia.org/wiki/Denormalization

【讨论】:

  • OP 的问题不在于他需要非规范化以提高性能。问题是他一开始就没有正确规范化。你也做到了。
  • 是的,我没有回答,“关系表是否应包含重复数据以加快查询速度”问题的标题对我来说是一种误导,我回答的问题标题不明确,所以我回答了一个在那里不需要的非特定答案。
猜你喜欢
  • 2011-05-10
  • 2015-05-14
  • 2019-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-14
  • 1970-01-01
相关资源
最近更新 更多