Обновление кэшированных подсчетов в MySQL - PullRequest
2 голосов
/ 16 июня 2010

Чтобы исправить ошибку, мне нужно перебрать все строки в таблице, обновив кешированное число детей до его реального значения.Структура вещей в таблице образует дерево.

В 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
  )

, за исключением того, что выше не работает (я понимаю, почему это«т) *. 1011 *

Ответы [ 2 ]

0 голосов
/ 16 июня 2010

Возможно, вы получили эту ошибку, верно?

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

Самый простой способ обойти это, вероятно, выбрать число дочерних элементов во временную таблицу, а затем присоединиться к этой таблице для обновлений.1005 * Это должно сработать, если предположить, что глубина отношения родитель / потомок всегда равна 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;
0 голосов
/ 16 июня 2010

ваше обновление под-выбора должно работать; давайте попробуем немного подправить:

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
  )

Но это не супер эффективно, я думаю.

...