2011-07-04 48 views
3

我有这个标签系统来标记博客条目等。这些标签位于一张表中,仅包含标签名称和主键。然后,我有另一个使用标签的对象。在表中计数实例

它可能是这个样子:

_________________________________ 
| tags       | 
--------------------------------| 
| id | name     | 
|-------------------------------| 
| 1 | Scuba diving   | 
| 2 | Dancing     | 
--------------------------------- 

_________________________________ 
| tag_objects     | 
--------------------------------| 
| id | tag | object   | 
|-------------------------------| 
| 1 | 2 | 13    | 
| 2 | 2 | 18    | 
| 3 | 1 | 24    | 
--------------------------------- 

现在,我需要完成的是一列添加到标签表,被称为“事件”或什么的。对于标签中的每个标签,出现次数应设置为tag_objects中标签的使用次数。

所以基本上是这样(显然伪代码):

foreach(tags): 
    UPDATE tags 
     SET occurrences = (SELECT COUNT(id) 
          FROM tag_objects 
          WHERE tag = tags.id); 

当人们创造未来的新职位和东西,我只是有一个触发更新计数,但我有一对夫妇已经有数千行了,我需要先计算一下。我不知道如何做到这一点,所以任何援助将不胜感激。

回答

4

要做到这一点,最简单的方式提供的SQL,没有任何多余的表格,将是:

首先添加额外的字段:

mysql> alter table标签添加发生int 默认为0;

然后,只需更新此新字段的出现次数。

的MySQL>更新代码左加入(选择标签, 计数(ID),如从tag_objects 组按标签CNT)作为SUBQ上 tags.id = subq.tag设置 发生聚结=(subq.cnt ,0);

请注意使用左连接来确保所有标记都被计数,即使是未使用的标记也是如此。合并函数将NULL转换为0.

+0

这很好用。谢谢! –

0

我想你会得到更好的表现,如果你将递增和递减表tag_objects插入/删除触发器occurrences的值。

+0

当然,我将在未来做到这一点。不过,我正在一个已经有几千行的相当老的数据库上实现它。我只打算运行一次,然后添加一个触发器来更新它。 –

+0

这不一定是真的。这一切都取决于更新/插入/删除的数量!如果这个数字很大,那么触发器可能实际上锁定标签表的时间太长了,以至于事情变慢了很多! – Eljakim

+0

在标准情况下,读取的标签数据不止变化。如果不是,标签的使用是有问题的。 – Gedrox

0

你的psuedeo代码将完全按照书面形式工作(没有foreach循环)。至少在oracle中,我假设MySQL允许您使用相关的子查询作为值。

1

你已经做了一个很好的工作,你的查询必须工作。

但是,这会导致可怕的表现。我建议你重新创建一个表格:

CREATE TABLE newTags AS 
SELECT t.id, t.name, COUNT(*) AS occurrences 
FROM tags t 
    INNER JOIN tag_objects to 
     ON to.tag = tags.id 
GROUP BY t.id, t.name 

这将是非常快的。

0

对于插入新行,您可以使用如下查询: INSERT INTO tags VALUES(x,y,z,1) ON DUPLICATE KEY UPDATE occurrences = occurrences+1; 我没有检查语法,但类似的东西。

1

除非您确实需要对数据进行非规范化处理,否则您应该远离这一点。在索引列上计数通常非常快。我是清洁和标准化的数据;-)

+0

它也伤害了我的灵魂,但是这个数据库已经瘫痪了,而且它已经经历了很多,比这更糟糕的事情。我们也有相当一部分流量,因此减少数据库在每个页面加载时所做的工作的任何方式都是需要的。 –

+0

啊!我看到...... ;-)在之前的工作中,我处于这种情况。我们花了几个月的时间进行优化,可以说它的工作效率为50%。我们通过chyanging硬件和升级(这是一个Oracle数据库)真正纠正了这个问题。 GL! –

1

我一般不想计算的值存储在数据库中列的大风扇 - 这是凌乱的,很容易不同步的,并违背正常化的神灵。但是,如果你真的必须有一个数据库实体,而不是实时计算,我会创建一个视图(http://dev.mysql.com/doc/refman/5.0/en/)。创建-view.html),其存储预先计算的值,使用由天蝎座

CREATE view tag_occurences AS 
SELECT t.id, t.name, 
COUNT(*) AS occurrences 
FROM tags t 
    INNER JOIN tag_objects to 
     ON to.tag = tags.id 
GROUP BY t.id, t.name 
+0

MySQL不支持物化视图,所以这不会存储任何东西。它会每次运行查询。 –

+0

它不需要实现 - 只是将查询填充到视图中,而不是每次都运行它。但是,像你一样,我只是运行查询,而不是通过视图。...... –

+0

你误会了。在MySQL中,查询视图与直接运行查询完全相同。它不预先计算任何值。使用视图不会影响优化,执行或表I/O。 –