题
我有一个数据库表,其中每一行都有一个随机生成的主键、一条消息和一个用户。每个用户大约有 10-100 条消息,但用户数量为 10k-50k。
我每天都会一次性为每个用户编写消息。我想在编写新消息之前丢弃每个用户的旧消息,以使表尽可能小。
现在我有效地这样做了:
delete from table where user='mk'
然后写入该用户的所有消息。我看到很多争用,因为我有很多线程同时执行此操作。
我确实有一个额外的要求,即为每个用户保留最新的消息集。
我无法直接访问数据库。我试图根据一些二手反馈来猜测问题。我关注这种情况的原因是删除查询显示了很多等待时间(再次 - 据我所知)加上它是新添加的功能。
有人可以提供任何建议吗?
最好是:
select key from table where user='mk'
然后从那里删除单独的行?我认为这可能会导致不那么残酷的锁定。
解决方案
没有,它始终是更好地在一组行不是一系列“行由行”的执行一个SQL语句(或汤姆·凯特称“慢的慢”)操作。当你说你是“看到了很多争论的”,你看到的是什么呢?一个明显的问题:被列USER索引
(当然,在列名不能真正是用户在Oracle数据库中,因为它是一个保留字!)
编辑::您曾经说过,列中的用户不被索引。这意味着每个删除将涉及到50K×100 = 500万行(或充其量10K×10 = 100,000行)的全表扫描删除仅仅10-100行。在用户添加一个索引可以解决您的问题。
其他提示
如果您为每个用户做日常,为什么不从表中删除所有记录在一个单独的语句?或甚至
truncate table whatever reuse storage
/
修改强>
我之所以认为这种做法是过程看起来像一个结算之前淘汰旧消息的用户消息的日常批量上传。也就是说,业务规则在我看来,是“表将只举行一次一天的消息对于任何给定的用户”。如果这个过程是为每个用户做然后单次操作将是最有效的。
但是,如果用户不每天获得一组新的消息的和的存在是需要我们的子公司规则是保留最近的消息集为每个用户,然后轰击整个表会是错的。
您确定您所看到的锁争用?它更有可能的是,你看到磁盘争由于过多并发(但不相关的更新)。该解决方案是简单地减少您正在使用的线程数:更少的磁盘争将意味着更高的总吞吐量
我想你需要定义你的要求更清楚一点......
有关实例。如果你知道你想要写的消息,插入的ID到一个临时表,索引它的ID和批量删除谁的用户。这样,你就发射了线程都在做两件事情。写的用户的ID到一个临时表,写入该消息到另一个临时表。然后,当线程完成执行时,主线程应该
DELETE * FROM消息INNER JOIN TEMP_MEMBERS ON ID = TEMP_ID
INSERT INTO信息选择* FROM TEMP_messges
我不是熟悉Oracle语法,但是这是我想接近它,如果用户的消息都在快速连续做的方式。
希望这有助于
<强>跟你的DBA 强>
他是来帮助你。当我们的DBA需要访问从开发商的一些东西,例如这个,假设我们将提供该任务对你的支持。如果你的代码的时间太长,完成和时间显示在数据库被捆绑起来,你的DBA就能看到底是怎么回事上,并提供建议,甚至可能解决的问题,而你改变任何东西。
只是扫视您的问题声明,它不会出现,你会看的竞争问题,但我不知道你的底层结构什么。
说真的,跟你的DBA。他可能会喜欢看一些有趣的东西,而不是规划的最新CPU部署。
这可能加快速度:
创建的查找表:
create table rowid_table (row_id ROWID ,user VARCHAR2(100));
create index rowid_table_ix1 on rowid_table (user);
运行夜间作业:
truncate table rowid_table;
insert /*+ append */ into rowid_table
select ROWID row_id , user
from table;
dbms_stats.gather_table_stats('SCHEMAOWNER','ROWID_TABLE');
然后删除记录时:
delete from table
where ROWID IN (select row_id
from rowid_table
where user = 'mk');
你自己的建议看起来非常明智。小批量锁定有两个优点:
- 交易量将会变小
- 锁定一次仅限于几行
批量锁定应该是一个很大的进步。