选择最佳查询

时间:2013-04-24 05:17:43

标签: sql oracle indexing

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

第一个版本:

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之间变化是否合理地为此表添加索引?

3 个答案:

答案 0 :(得分: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

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

答案 1 :(得分:2)

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

如果要插入大量行,则索引会减慢插入速度,因为每个插入索引也必须更新[我不建议使用ID索引]。我有两种解决方案:

  1. 您可以在插入前删除索引,然后在插入后重新创建索引。
  2. 使用反向键索引。请检查此链接:http://oracletoday.blogspot.in/2006/09/there-is-option-to-create-index.html。反向键索引可能会影响您的查询,因此会有折衷。

答案 2 :(得分:0)

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

E.g。 (仅用于演示,未检查语法有效性,省略序列和触发器):

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是直接寻址存储块的物理存储标识,移动到另一台服务器后无法使用它,从备份中恢复等。但如果您需要这样的功能,可以从{{1}添加id列表格也可以my_log,并根据要求使用一个或另一个。