0

例如,我在 Oracle 数据库中有一个名为 my_table 的表。它是日志表的类型。它有一个名为“id”和“registration_number”的增量列,对于注册用户来说是唯一的。现在我想获得注册用户的最新更改,所以我在下面写了查询来完成这个任务:

第一个版本:

SELECT t.*
FROM my_table t
WHERE t.id =
  (SELECT MAX(id) FROM my_table t_m WHERE t_m.registration_number = t.registration_number
  );

第二个版本:

SELECT t.*
FROM my_table t
INNER JOIN
  ( SELECT MAX(id) m_id FROM my_table GROUP BY registration_number
  ) t_m
ON t.id = t_m.m_id;

我的第一个问题是建议使用上述哪个查询,为什么?第二个问题是,如果有时该表中有大约 70.000 条插入,但插入的行数大多在 0 到 2000 之间变化,是否可以向该表添加索引?

4

3 回答 3

2

分析查询可能是为每个注册用户获取最新更改的最快方法:

SELECT registration_number, id
FROM (
  SELECT
    registration_number,
    id,
    ROW_NUMBER() OVER (PARTITION BY registration_number ORDER BY id DESC) AS IDRankByUser
  FROM my_table
)
WHERE IDRankByUser = 1

至于索引,我假设您已经有一个索引 by registration_number。一个额外的索引id将有助于查询,但可能不会太多,也可能不足以证明索引的合理性。我这么说是因为如果你一次插入 70K 行,额外的索引会减慢INSERT. 您必须进行试验(并检查执行计划)以确定索引是否值得。

于 2013-04-24T05:42:39.710 回答
2

为了检查更快的查询,您应该检查执行计划和成本,它会给您一个公平的想法。但我同意 Ed Gibbs 的解决方案,因为分析使查询运行得更快。如果你觉得这个表会变得非常大,那么我会建议对表进行分区并使用本地索引。他们肯定会帮助您形成更快的查询。

如果您要插入大量行,则索引会减慢插入速度,因为每个插入索引也必须更新[我不推荐 ID 上的索引]。我为此想到了两种解决方案:

  1. 您可以在插入之前删除索引,然后在插入后重新创建它。
  2. 使用反向键索引。检查此链接: http: //oracletoday.blogspot.in/2006/09/there-is-option-to-create-index.html。反向键索引可能会稍微影响您的查询,因此会有所取舍。
于 2013-04-24T07:18:24.173 回答
0

如果您寻找更快的解决方案并且确实需要维护每个用户的最后活动列表,那么最强大的解决方案是维护具有唯一registration_number值的单独表以及rowid在日志表中创建的最后记录。

例如(仅用于演示,不检查语法有效性,省略序列和触发器):

create table my_log(id number not null, registration_number number, action_id varchar2(100))
/

create table last_user_action(refgistration_number number not null, last_action rowid)
/

alter table last_user_action 
  add constraint pk_last_user_action primary key (registration_number) using index 
/

create or replace procedure write_log(p_reg_num number, p_action_id varchar2)
is
  v_row_id rowid;
begin

  insert into my_log(registration_number, action_id) 
  values(p_reg_num, p_action_id)
  returning rowid into v_row_id;

  update last_user_action 
  set last_action = v_row_id 
  where registration_number = p_reg_num;

end;
/

使用这样的模式,您可以简单地查询每个用户的最后操作,并具有良好的性能:

select 
from
  last_user_action lua,
  my_log           l
where
  l.rowid (+) = lua.last_action

Rowid 是直接寻址存储块的物理存储标识,在移动到另一台服务器、从备份恢复等后您将无法使用它。但是如果您需要这样的功能,也可以简单地从表中添加id列,并根据具体情况使用一个或另一个要求。my_loglast_user_action

于 2013-04-24T16:27:25.600 回答