1

我有一个数据库表,其中每一行都有一个随机生成的主键、一条消息和一个用户。每个用户大约有 10-100 条消息,但有 10k-50k 用户。

我每天一次为每个用户写消息。我想在编写新消息之前为每个用户丢弃旧消息,以使表格尽可能小。

现在我有效地做到了这一点:

delete from table where user='mk'

然后为该用户编写所有消息。我看到很多争论,因为我有很多线程同时在做这件事。

我确实有一个额外的要求,即为每个用户保留最新的一组消息。

我无法直接访问数据库。我试图根据一些二手反馈来猜测问题。我关注这种情况的原因是删除查询显示了很多等待时间(再次 - 据我所知),而且它是一个新添加的功能。

任何人都可以提供任何建议吗?

是否会更好:

select key from table where user='mk'

然后从那里删除个别行?我认为这可能会导致不那么残酷的锁定。

4

7 回答 7

4

如果您每天为每个用户执行此操作,为什么不在单个语句中删除表中的每条记录?甚至

truncate table whatever reuse storage
/

编辑

我建议这种方法的原因是该过程看起来像是每天批量上传用户消息,然后清除旧消息。也就是说,在我看来,业务规则是“对于任何给定用户,该表只能保存一天的消息”。如果为每个用户完成此过程,那么单个操作将是最有效的。

但是,如果用户没有每天收到一组新消息,并且有一条附属规则要求我们为每个用户保留最新的一组消息,那么 zapping 整个表将是错误的。

于 2009-10-30T12:36:41.113 回答
3

不,在一组行上执行单个 SQL 语句总是比一系列“逐行”(或 Tom Kyte 所说的“逐行”)操作更好。当你说你“看到很多争论”时,你到底看到了什么?一个明显的问题:列 USER 是否已编入索引?

(当然,列名在Oracle数据库中不能真的是USER,因为它是保留字!)

编辑:你说过列 USER 没有被索引。这意味着每次删除将涉及最多 50K*100 = 500 万行(或最多 10K * 10 = 100,000 行)的全表扫描,仅删除 10-100 行。在 USER 上添加索引可能会解决您的问题。

于 2009-10-30T12:34:36.513 回答
0

你确定你看到锁争用吗?由于太多并发(但不相关的更新),您似乎更有可能看到磁盘争用。解决方案就是减少您正在使用的线程数:更少的磁盘争用将意味着更高的总吞吐量。

于 2009-10-30T12:34:41.257 回答
0

与您的 DBA 交谈

他在那里帮助你。当我们的 DBA 从开发人员那里拿走诸如此类的事情时,假设我们将为您提供该任务的支持。如果您的代码完成时间过长,并且该时间似乎被数据库占用,您的 DBA 将能够准确地查看正在发生的事情并提供建议,甚至可能在您不进行任何更改的情况下解决问题。

只是浏览一下您的问题陈述,您似乎不会在查看争用问题,但我对您的底层结构一无所知。

真的,和你的 DBA 谈谈。他可能会喜欢看一些有趣的东西,而不是计划最新的 CPU 部署。

于 2009-10-30T14:45:39.387 回答
0

我认为你需要更清楚地定义你的要求......

例如。如果您知道要为其编写消息的所有用户,请将 ID 插入临时表中,在 ID 上建立索引并批量删除。然后你正在触发的线程正在做两件事。将用户的 ID 写入临时表,将消息写入另一个临时表。然后当线程完成执行时,主线程应该

DELETE * FROM Messages INNER JOIN TEMP_MEMBERS ON ID = TEMP_ID

插入消息 SELECT * FROM TEMP_messges

我不熟悉 Oracle 语法,但如果用户消息都快速连续完成,我会采用这种方式。

希望这可以帮助

于 2009-10-30T13:35:14.753 回答
-2

这可能会加快速度:

创建查找表:

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');
于 2009-10-30T15:19:14.967 回答
-4

你自己的建议似乎很明智。小批量锁定有两个好处:

  • 交易会更小
  • 一次锁定将仅限于几行

分批锁定应该是一个很大的进步。

于 2009-10-30T12:37:23.623 回答