如何从Oracle快速选择数据

时间:2010-07-27 15:19:10

标签: performance oracle

我有以下Oracle表:

GAMES    
    id_game int
    id_user int
    dt_game DATE

在创建新记录之前,我必须检查同一个用户是否每天都没有插入N次游戏。

我实际上是以这种方式选择今天玩的游戏数量:

select count(1) as num from GAMES 
where id_user=ID_USER and
to_char(dt_game,'DD/MM/YYYY')=to_char(sysdate,'DD/MM/YYYY')

我不太喜欢它:有更好的方法吗?

提前致谢 角

4 个答案:

答案 0 :(得分:6)

日期转换有点无意义并且阻止使用该列的任何索引;您可以使用dt_game > trunc(sysdate)简化该位。

答案 1 :(得分:4)

在插入新行之前检查表并计算行数存在问题(与并发性有关)。

让我们说用户目前玩了9场比赛,你想把行限制在10 ..

如果你打开两个不同的会话,那么他们两个将看到9个游戏的当前未提交的值,因此两个游戏都被允许,到交易完成时,用户将玩11个游戏......违反了你试图强制执行的规则。

答案 2 :(得分:2)

您可以使用唯一约束来确保在特定日期可以插入固定的最大记录数。例如,如果N = 5:

CREATE TABLE GAMES (
  id_game         NUMBER NOT NULL,
  id_user         NUMBER NOT NULL,
  dt_game         DATE   NOT NULL,
  user_game_count NUMBER NOT NULL,
  CONSTRAINT max_games_per_day
  CHECK (user_game_count BETWEEN 1 AND 5),
  CONSTRAINT dt_game_notime
  CHECK (dt_game = TRUNC(dt_game)),
  CONSTRAINT games_unique
  UNIQUE (id_user, dt_game, user_game_count),
);

max_games_per_day约束意味着它只能采用5个不同值中的一个。 dt_game_notime约束意味着我们不会获得各种时间值。最后,唯一约束确保对于任何特定日期和用户,它们最多只能插入5行。

答案 3 :(得分:1)

在Oracle中,您可以在id_user,to_char(dt_game,'DD / MM / YYYY')上创建function based index以提高查找性能。