2009-06-08 85 views
0

我有两个表,像这样的:标准化这张表是否更快?

表人物:
VARCHAR名称
INTEGER年龄

表信息
VARCHAR消息
VARCHAR名称

有数以百计的插入和用这样的查询删除消息表:

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

我的问题是,是否值得在People中添加一个ID字段并将该用户作为消息中的ID引用?以下查询会更快吗?

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

我以为最初插入和删除通过搜索id会比通过字符搜索更快。但速度要快多少?速度是否会增加需要对用户表进行额外查询以查找ID的性能?

+0

如果客户端代码距离数据库服务器很远,SELECT + DELETE将会非常昂贵;如果客户端代码和数据库服务器是共置的,它将会更加昂贵。单个语句 - 可能DELETE FROM消息WHERE Id =(SELECT ID FROM Users WHERE Name ='John') - 会更高效。给优化器一些优化,它会为你创造奇迹。对待它就像一个愚蠢的文件管理器,它会为你执行。 – 2009-06-09 07:42:29

回答

5

,额外的查询将使它稍微慢一点(当然也有对名称的长度,数据库类型等相关性)

但会发生什么当用户改变他的名字,当你想删除一个用户等等。这种设计会给你带来很多痛苦。无论这个微小的性能问题如何,正常化会更好,

+0

+1对于“速度不是万能的”,但从长远来看,音效设计确实值得回报! – 2009-06-08 19:11:32

1

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

3

它更快吗?然而,只有性能分析才能说明问题。 。 。

IS更好的做法是在Person上放置一个id列,并在ID上放置一个来自Message to Person的外键约束(假设所有消息只能发送给Person表中的人员)。

您仍然可以在一个声明中

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

和数据库将优化这个删除了消息,所以它比两个语句(比单独的选择& delete语句即更快)

远快你可以在外键约束上指定级联删除,这样当您删除某个人时,所有发给该人的消息也会自动删除。

至于你说在这里看到更多关于Foreign Keys

+0

我认为“id =(...)”应该是“id IN(...)”,尽管它可能取决于所使用的SQL的风格。 – 2009-06-08 18:24:06

+0

@Carl:好点 – 2009-06-09 07:25:42

1

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

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

如果他使用SQL Server,他将需要打破微软的双重FROM语法。 – 2009-06-08 18:06:39

+0

这个连接对性能有很大的影响吗? – erotsppa 2009-06-08 18:20:51

4

一个人的名字永远不是一个好的主键,因为名字不是唯一的。他们随着时间的推移而变化FAr最好使用代理键(并且是的,Int上的联接通常更快,并且您可以加入删除许多数据库中不使用较慢子查询的脚本),尤其是因为名称通常长于几个字符。

1

以我的经验,网站后端的用户表是其中的一个表,几乎可以在100%的时间内保留在内存中。它对任何活动都非常重要,所以它永远不会脱离页面缓冲区。所以我会(并且)肯定会使用userId这样的所有引用的路线。

1

要将确切问题,用这么小的模式,转储原来消息表,非规范化会更快的内容。查询计划将更小并且更易于优化,并且不会有连接开销。

一般来说,它要复杂得多。

这是否是正确的做法是一个问题。为此,从标准化的设计开始,但是如果有充分的理由这么做的话,愿意并准备去规范化。有时会出现非规范化的合法原因,尽管通常数据的收益抵消了任何性能损失。

标准化数据更容易维护,通常更灵活。为了获得灵活性,使用数字pkey可以让多个人命名为相同的名称。您可以轻松地向添加更多字段。运行报告可以更轻松地查看系统中的所有人员,而无需全部扫描消息

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

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

0

你应该不需要担心优化,直到你有一个好的设计。

现在,我认为很难说这是否是一个不切实际的玩具问题,但通常情况下,您打算设计一个主键和外键关系,而且这个关键是非常不可能是一个varchar。

它可能是一个GUID或它可能是一个int,但无论哪种方式,你将至少有一个非聚集索引,它可能是一个聚集索引,并且你将有一个非聚集索引对重要数据(例如用户名)的聚集索引,因此最终整个系统的性能(而不仅仅是这一个删除)将取决于这些表的固定标准化设计和良好的索引策略。

4

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

这不是一个标准化问题 - 如果你想允许人们改变他们的名字,你有一个性能和可​​伸缩性问题(需要更新消息表中的所有相关行)。

如果人们在系统中永远不会改变他们的名字,那么这不是问题。在这种情况下,Name与ID一样好 - 虽然有些DBMS可能会使用索引编号而不是索引字符串(?)更好地执行。

删除的性能是另一回事 - 我想说如果你已经有了一个唯一的名字,那么通过名字删除将比根据ID删除查找(或加入)更快 - 但是你又一次会想要做你自己的基准。

0

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

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

0

备注:不要忘记将索引放在要加入表格的列上,如果它们不在那里的话。