规范化这个表是否更快?

时间:2009-06-08 17:44:00

标签: sql database optimization rdbms

我有两张桌子,如:

表人:
VARCHAR名称
INTEGER年龄

表格留言
VARCHAR消息
VARCHAR名称

Message表中有数百个插入和删除,其中包含以下查询:

insert into Message VALUES ('Hello there', 'John');
delete from Message where name = 'John';

我的问题是,在People中添加ID字段并在Message中引用User作为id是否值得?以下查询会更快吗?

FIRST - select id from User where name = 'John'
THEN - delete from Message where id = $id

我认为首先通过搜索id来插入和删除比通过字符搜索更快。但要快多少?速度是否会因为需要额外查询到User表以找到id而影响性能?

11 个答案:

答案 0 :(得分:5)

正如你所说,额外的查询会使它变得更慢(当然,它依赖于名称的长度,数据库类型等)。

但是当用户更改其名称,何时要删除用户等时会发生什么?那种设计会给你带来很多痛苦。无论这个微小的性能问题如何,最好进行标准化,

答案 1 :(得分:4)

一个人的名字永远不是一个好的主键,因为名字不是唯一的。它们会随着时间而改变。 FAr最好使用代理键(是的,对Int的连接通常更快,你可以加入许多数据库中的删除staments而不使用较慢的子查询),特别是因为名称往往长于几个字符。

答案 2 :(得分:4)

假设您对People.Name有唯一约束,并且Message.Name和People.Name之间存在引用完整性约束,那么您的设计已经已经规范化了。

这不是规范化的问题 - 如果你想让人们改变他们的名字,你就会遇到性能和可扩展性问题(需要更新Message表中的所有相关行)。

如果人们从未在您的系统中更改其名称,那么这不是问题。在这种情况下,Name几乎与ID一样好 - 尽管某些DBMS可能在索引编号而不是索引字符串(?)中表现更好。

删除的性能是另一回事 - 我会说如果你已经拥有一个唯一的名称,那么按名称删除将比通过ID进行查找(或加入)删除更快 - 但是你再次'我想做你自己的基准测试。

答案 3 :(得分:3)

更快吗?但是,只有剖析才能说明。 。

IS 更好的做法是在Person上放置一个id列,并在Message上将一个外键约束从Message放到Person上(假设所有消息只能转到Person表中的人)。

您仍然可以在一个声明中删除邮件

delete from Message where id IN (select id from Person where Name = 'John')

并且数据库将对此进行优化,因此它比两个语句快得多(即比单独的select和amp; delete语句更快)

您可以在外键约束上指定级联删除,这样当您删除Person时,所有发送给此人的邮件也会自动删除。

有关Foreign Keys

的详情,请参阅此处

答案 4 :(得分:1)

如果大多数名称都很短(不是15到20个字符长),并且表格已正确编入索引,那么您将从id字段接收的速度性能可以忽略不计。

答案 5 :(得分:1)

您不需要进行额外的查询。你可以这样做:

DELETE FROM Message 
INNER JOIN User 
  ON Message.id = User.id 
WHERE User.name = 'John'

答案 6 :(得分:1)

根据我的经验,网站后端的用户表是100%的时间内几乎停留在内存中的表之一。它是任何活动的核心,因此它永远不会超出页面缓冲区。所以我会(而且)肯定会使用userId这样的所有引用的路径。

答案 7 :(得分:1)

对于完全问题,使用如此小的架构来转储原始消息表的内容,非规范化将更快。查询计划将更小,更容易优化,并且不会有连接开销。

总的来说,它要复杂得多。

是否正确的做法是一个问题。为此,从标准化设计开始,但如果有令人信服的理由,愿意并准备进行非规范化。非规范化有时会有合理的理由,但通常归一化数据的增益会抵消任何性能损失。

规范化数据更易于维护,通常更灵活。为了灵活性,使用数字p键可以让多个名为同名的人。您可以轻松地向人员添加更多字段。如果不扫描所有消息,则可以更轻松地生成报告以查看系统中的所有人。

但表现可能是一个因素。给定两个表中的数据,数据库有几个关于如何加入的选项。它可以使用消息作为基表,以及如何完成连接会影响事物(嵌套循环,散列连接,排序/合并等)。< / p>

但除此之外,规范化实际上可以更快。如果您的架构比您描述的更复杂怎么办?假设您的表包含50个与HR相关的字段,而您的消息表只有一个20个字符的消息字段。如果你有两个人的情况但是100k消息,非规范化实际上会更快。这是因为I / O是数据库的最大限制因素。如果要将所有数据转储到一个查询中,则规范化数据将仅获取这50个字段,并且消息表将密集地包含数据。在非规范化版本中,消息的每一行将包含51个字段,您将大幅增加I / O的数量以获得相同的结果。

答案 8 :(得分:0)

在你有一个好的设计之前,你不必担心优化。

现在,我认为很难说这是不是一个不切实际的玩具问题,但通常情况下,你会考虑设计一个主键和外键关系,这个键是非常不太可能是varchar。

它可能是一个GUID,也可能是一个int,但无论哪种方式,你将至少拥有一个非聚集索引,可能是一个聚簇索引,你将拥有一个非聚合索引。像用户名这样的重要数据的聚簇索引,因此最终整个系统的性能(而不仅仅是这一个删除)将取决于这些表的可靠规范化设计和良好的索引策略。

答案 9 :(得分:0)

关于IO和可维护性。如果你的varchar包含少于4个字节,那么如果使用varchar而不是整数,查询将会更快。但这并不是一个很大的改进,如果你需要更改名称,你会失去很多性能!消息表中的每一行都需要更新(例如删除和插入)。

如果使用整数,则只存储4个字节用于对用户表的引用。如果你在用户表中使用ID和名称的覆盖索引,那么这只是一个小小的开销。用户表可能会保留在缓存中,具体取决于您在用户表中预期的行数以及您拥有的内存量。在这种情况下,您将进行逻辑扫描,而不是速度慢得多的物理扫描。

答案 10 :(得分:0)

附注:不要忘记将索引放在要加入表的列上(如果它们不存在的话)。