【问题标题】:How to fastly select data from Oracle如何快速从 Oracle 中选择数据
【发布时间】:2020-07-08 17:17:44
【问题描述】:

我有以下 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')

我不太喜欢。有没有更好的方法?

提前致谢。

【问题讨论】:

    标签: performance oracle


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

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

      假设用户当前玩了 9 场游戏,而您希望将行数限制为 10..

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

      【讨论】:

        【解决方案3】:

        您可以使用唯一约束来确保可以在特定日期插入固定的最大记录数。例如,如果 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 行。

        【讨论】:

        • 应用程序需要为感兴趣的 (id_user, dt_game) 发现 user_game_count 的下一个值。这可以在并发环境中可靠地完成而不锁定对表的访问吗?
        • 是 - 如果两个会话尝试插入具有相同 user_game_count 的行,一个会成功,另一个会引发异常。然后只需使用“退出/重试”循环对应用程序进行编码即可。
        • 您看到这张表是每个用户每个日期有 5 行(如果他玩 5 场游戏)还是 1 行计数为 5? max_games_per_day 约束让我相信会有一个计数为 5 的行......但是 games_unique 约束和您的评论“任何特定的日期和用户,他们最多只能插入 5 行”似乎表明并非如此。如果您插入 5 行(甚至不插入),为什么需要在 games_unique 约束中包含 user_game_count?相反,它不应该包含 User_id、game_id 和 trunc(game_date) 吗?
        • @Rajesh,如果 game_id 本身是唯一的,那么将其添加到约束将不会增加任何值,并且会破坏此功能。查看约束 max_games_per_day:它将 user_game_count 约束为恰好五个值:1、2、3、4 或 5。为了将表限制为每个用户每天 5 行,这是必需的。
        【解决方案4】:

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

        【讨论】:

        • 在上面的表格描述中,dt_game 列已经是一个日期。所以将它转换为字符串是没有意义的。
        猜你喜欢
        • 2012-12-16
        • 1970-01-01
        • 1970-01-01
        • 2016-05-16
        • 2012-06-07
        • 2019-08-27
        • 1970-01-01
        • 2022-01-20
        • 1970-01-01
        相关资源
        最近更新 更多