我有这个标记系统用于标记博客条目等。标签位于一个表中,仅包含标签名称和主键。然后我有另一个表格,其中包含使用标签的对象。
看起来像这样:
_________________________________
| tags |
--------------------------------|
| id | name |
|-------------------------------|
| 1 | Scuba diving |
| 2 | Dancing |
---------------------------------
_________________________________
| tag_objects |
--------------------------------|
| id | tag | object |
|-------------------------------|
| 1 | 2 | 13 |
| 2 | 2 | 18 |
| 3 | 1 | 24 |
---------------------------------
现在,我需要完成的是在tags表中添加一个列,称为“eventss”或其他东西。对于标记中的每个标记,应将出现次数设置为tag_objects中标记的使用次数。
所以基本上就像(显然是伪代码):
foreach(tags):
UPDATE tags
SET occurrences = (SELECT COUNT(id)
FROM tag_objects
WHERE tag = tags.id);
当人们在将来创建新帖子和内容时,我只会触发更新计数,但我已经有几千行,我需要先计算。我不知道该怎么做,所以任何帮助都会受到赞赏。
答案 0 :(得分:4)
最简单的方法是在没有任何额外表的情况下执行此操作:
首先添加额外字段:
的MySQL> alter table标签添加发生在int 默认为0;
然后只需用出现次数更新这个新字段。
的MySQL>更新标签左连接(选择标签, count(id)作为来自tag_objects的cnt 按标签分组)as subq on tags.id = subq.tag set 发生聚结=(subq.cnt,0);
请注意使用左连接以确保计算所有标记,甚至是未使用的标记。 coalesce-function将NULL转换为0。
答案 1 :(得分: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
这将非常快。
答案 2 :(得分:1)
除非你真的需要对数据进行非规范化,否则你应该远离它。对索引列进行计数通常非常快。我是清洁和规范化数据的忠实粉丝; - )
答案 3 :(得分:1)
我通常不希望将计算值存储在数据库的列中 - 它很乱,很容易失去同步,并且冒犯了规范化的神。
但是,如果你真的必须有一个带有计数的数据库实体,而不是动态计算,我会创建一个视图(http://dev.mysql.com/doc/refman/5.0/en/create -view.html)使用Scorpio提供的SQL
存储预先计算的值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
答案 4 :(得分:0)
如果您要在表occurrences
插入/删除触发器上递增和递减tag_objects
的值,我认为您将获得更好的性能。
答案 5 :(得分:0)
你的psuedeo代码将完全按照书面编写(没有foreach循环)。至少它会在oracle中,我假设MySQL允许你使用相关的子查询作为值。
答案 6 :(得分:0)
对于插入新行,您可以使用如下查询:
INSERT INTO tags VALUES(x,y,z,1) ON DUPLICATE KEY UPDATE occurrences = occurrences+1;
我没有检查语法,但有类似的东西。