更新MySQL中的缓存计数

时间:2010-06-16 15:50:08

标签: mysql ruby-on-rails caching tree children

为了修复错误,我必须遍历表中的所有行,将缓存的子计数更新为其实际值。表中的东西的结构形成一棵树。

在rails中,以下是我想要的:

Thing.all.each do |th|
  Thing.connection.update(
    "
      UPDATE #{Thing.quoted_table_name} 
        SET children_count = #{th.children.count}
        WHERE id = #{th.id}
    "
  )
end

有没有办法在单个MySQL查询中执行此操作? 或者,有没有办法在多个查询中执行此操作,但在纯MySQL中?

我想要像

这样的东西
UPDATE table_name
  SET children_count = (
    SELECT COUNT(*) 
      FROM table_name AS tbl 
      WHERE tbl.parent_id = table_name.id
  )

除了以上不起作用(我明白为什么不行)。

2 个答案:

答案 0 :(得分:0)

您的子选择更新应该有效;让我们试试一下:

UPDATE table_name
  SET children_count = (
    SELECT COUNT(sub_table_name.id) 
      FROM sub_table_name 
      WHERE sub_table_name.parent_id = table_name.id
  )

或者如果子表是同一个表:

UPDATE table_name as top_table
  SET children_count = (
    SELECT COUNT(sub_table.id) 
      FROM (select * from table_name) as sub_table
      WHERE sub_table.parent_id = top_table.id
  )

但我猜测这不是超级高效。

答案 1 :(得分:0)

你可能有这个错误,对吧?

ERROR 1093 (HY000): You can't specify target table 'table_name' for update in FROM clause

最简单的方法是将子计数选择到临时表中,然后加入该表进行更新。

这应该有效,假设父/子关系的深度始终为1.根据您的原始更新,这似乎是一个安全的假设。

我在表上添加了一个显式写锁,以确保在创建临时表后没有修改任何行。如果您能够在此更新期间锁定它,则应该只执行此操作,这取决于数据量。

lock tables table_name write;

create temporary table temp_child_counts as
select parent_id, count(*) as child_count
from table_name 
group by parent_id;

alter table temp_child_counts add unique key (parent_id);

update table_name
inner join temp_child_counts on temp_child_counts.parent_id = table_name.id
set table_name.child_count = temp_child_counts.child_count;

unlock tables;