让我们从一个例子开始。有桌子:
CREATE TABLE X (
id INT(32) NOT NULL auto_increment,
account INT(32),
value INT(32),
primary KEY (id)
)
我想要实现的是确保给定帐户具有指定的值集(并且只有这些值)。基本上,如何有效地在下面做:
delete from X where account = 5;
insert into X (account, value) values
(5, 0),
(5, 2),
(5, 3)
...
(5, 99);
需要注意的是,通常只有一个值会发生变化(出现或消失)。 几乎我有一组值会发生变化,但是我不需要接收增量,而是需要有效地反映差异。给定帐户的价值不会超过100个,通常只有2-3个。这些变化每秒发生数千次。对同一帐户的更改很少见(通常只有几个,但偶尔会更多)。
我想到的是设置id帐户* 1000 + sequence_id以增加具有相同帐户的行的数据位置。而且我可以做(伪代码)而不是删除+重新插入:
$current_values = select value from X where account = 5;
$to_add = $new_values not in $current_values
$to_remove = $current_values not in $new_values
delete from X where value in $to_remove
insert into X (account, value) values (5, $to_add[0]), (5, $to_add[1])...
我怎样才能做得更好?
答案 0 :(得分:0)
使用不存在因此单独保留现有记录,并删除您未在列表中提供的那些记录。
Delete from X t1 where not exists
(Select 1 from X t2 where t1.account=t2.account and t1.value=t2.value
and value in (0,2,3,...99))
现在如果你有办法识别0,2,3 ... 999而不必传入它,那就更好了,因为你可能会使用in子句遇到限制。
这一切都包含在一个声明中,使其不易受多个用户使用同一帐户的问题的影响。
答案 1 :(得分:0)
将INDEX(account)
添加到X。
将传入的信息收集到临时表中。 tmp
。
DELETE X FROM X, ( SELECT DISTINCT account FROM tmp ) y WHERE x.account=y.account;
[检查语法,并在投入生产前进行测试。]
INSERT INTO X (account, value) SELECT (account, value) FROM tmp;
如果您使用InnoDB,我建议BEGIN; DELETE...; INSERT...; COMMIT;
。这将使其他连接无法找到即将重新插入的行。
如果那太慢了;让我们进一步讨论。
抛开:INT(32)
- “(32)”意味着什么。 INT是一个4字节的整数,无论其后面的值如何。