【问题标题】:Can I define a lifetime for each row of MySQL's table?我可以为 MySQL 表的每一行定义一个生命周期吗?
【发布时间】:2016-06-27 22:38:20
【问题描述】:

我有一张这样的桌子:

// banned
+----+---------+---------------+
| id | user_id |   unix_time   |
+----+---------+---------------+
| 1  | 32534   | 1467066745524 |
| 2  | 43535   | 1467066745541 |
| 3  | 24352   | 1467066745618 |
| 4  | 88734   | 1467066746093 |
+----+---------+---------------+

实际上我需要在插入时为每一行定义一个过期时间。这在 MySQL 中可能吗? (我听说 Redis 可以,那么 MySQL 呢?)


所以我想要这样的东西:

// banned
+----+---------+---------------+
| id | user_id |   unix_time   |
+----+---------+---------------+
| 1  | 32534   | 1467066745524 | -- removing this row automatically in 10 min
| 2  | 43535   | 1467066745541 | -- removing this row automatically in 1 hour
| 3  | 24352   | 1467066745618 | -- removing this row automatically 2 day
| 4  | 88734   | 1467066746093 | -- removing this row automatically 8 hours min
+----+---------+---------------+

如您所见,每一行都有任意的生命周期。

【问题讨论】:

  • 如果到期时间是每个用户随机的,那么我认为您必须自己插入该数据。只需将到期日期设置为当前日期 + 允许用户存在的秒数/分钟/天数/等。至于删除,我不相信有什么办法可以强制mysql删除记录。如果日期过期,您必须创建一个作业来删除记录。
  • 为什么这个过期时间很重要?例如,如果您不希望用户在过期日期之后登录系统,则在身份验证期间检查该日期。
  • 此链接可能对您有所帮助stackoverflow.com/questions/11038675/…

标签: mysql sql database


【解决方案1】:

您可以创建一个每分钟运行的事件并删除旧记录,如下所示:

启用调度程序

SET GLOBAL event_scheduler = ON;

创建 EVENT 每分钟运行一次

CREATE EVENT cleanup
ON SCHEDULE EVERY 1 MINUTE
DO 
 DELETE
  FROM yourTable
  WHERE unix_time < UNIX_TIMESTAMP();

示例

MariaDB [yourschema]> SET GLOBAL event_scheduler = ON;
Query OK, 0 rows affected (0.00 sec)

MariaDB [yourschema]> SHOW GLOBAL VARIABLES LIKE 'event_scheduler';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| event_scheduler | ON    |
+-----------------+-------+
1 row in set (0.00 sec)

MariaDB [yourschema]> SHOW PROCESSLIST;
+-----+-----------------+-----------------+------------+---------+------+-----------------------------+------------------+----------+
| Id  | User            | Host            | db         | Command | Time | State                       | Info             | Progress |
+-----+-----------------+-----------------+------------+---------+------+-----------------------------+------------------+----------+
|  28 | root            | localhost:53255 | yourSchema | Sleep   |   11 |                             | NULL             |    0.000 |
|  29 | root            | localhost:53256 | NULL       | Sleep   |   28 |                             | NULL             |    0.000 |
|  34 | event_scheduler | localhost       | NULL       | Daemon  | 6603 | Waiting for next activation | NULL             |    0.000 |
| 316 | root            | localhost       | yourschema | Query   |    0 | init                        | SHOW PROCESSLIST |    0.000 |
+-----+-----------------+-----------------+------------+---------+------+-----------------------------+------------------+----------+
4 rows in set (0.00 sec)

MariaDB [yourschema]>
MariaDB [yourschema]> SHOW events;
Empty set (0.01 sec)

MariaDB [yourschema]> DROP EVENT IF EXISTS cleanup;
Query OK, 0 rows affected, 1 warning (0.00 sec)

MariaDB [yourschema]> CREATE EVENT cleanup
    -> ON SCHEDULE EVERY 5 SECOND  ON COMPLETION PRESERVE ENABLE
    -> DO
    ->  DELETE
    ->   FROM schedulerTable
    ->   WHERE expire_unix_time < UNIX_TIMESTAMP() LIMIT 10;
Query OK, 0 rows affected (0.00 sec)

MariaDB [yourschema]> INSERT INTO schedulerTable VALUES
    -> (NULL,100,UNIX_TIMESTAMP(now() + INTERVAL 30 SECOND)),
    -> (NULL,101,UNIX_TIMESTAMP(now() + INTERVAL 40 SECOND)),
    -> (NULL,111,UNIX_TIMESTAMP(now() + INTERVAL  1 MINUTE));
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

MariaDB [yourschema]> SELECT * FROM schedulerTable;SELECT SLEEP(20);
+-------------+---------+------------------+
| id_rubrique | id_stat | expire_unix_time |
+-------------+---------+------------------+
|           1 |     100 |       1467074632 |
|           2 |     101 |       1467074642 |
|           3 |     111 |       1467074662 |
+-------------+---------+------------------+
3 rows in set (0.00 sec)

+-----------+
| SLEEP(20) |
+-----------+
|         0 |
+-----------+
1 row in set (20.00 sec)

MariaDB [yourschema]> SELECT * FROM schedulerTable;SELECT SLEEP(20);
+-------------+---------+------------------+
| id_rubrique | id_stat | expire_unix_time |
+-------------+---------+------------------+
|           2 |     101 |       1467074642 |
|           3 |     111 |       1467074662 |
+-------------+---------+------------------+
2 rows in set (0.00 sec)

+-----------+
| SLEEP(20) |
+-----------+
|         0 |
+-----------+
1 row in set (20.01 sec)

MariaDB [yourschema]> SELECT * FROM schedulerTable;SELECT SLEEP(20);
+-------------+---------+------------------+
| id_rubrique | id_stat | expire_unix_time |
+-------------+---------+------------------+
|           3 |     111 |       1467074662 |
+-------------+---------+------------------+
1 row in set (0.00 sec)


+-----------+
| SLEEP(20) |
+-----------+
|         0 |
+-----------+
1 row in set (20.01 sec)

MariaDB [yourschema]> SELECT * FROM schedulerTable;
Empty set (0.00 sec)

MariaDB [yourschema]>

【讨论】:

  • 此条件WHERE unix_time &lt; UNIX_TIMESTAMP() 始终为true。这样 EVENT 每次都会删除所有行。
  • 如果要将行删除到不同的时间,您必须将过期时间戳放在表的行中。我会在几分钟内添加一个样本
  • @stack - 我在我的答案中添加了一个完整的示例
  • 虽然这可行,但 (1) 这具有非常高的粒度,并且 (2) 它会产生运行事件以在可能不需要时进行清理的开销。运行这么频繁的事件,实在是太浪费数据库资源了。
  • @Gordon Linoff - 是的,正确的 - 更好的解决方案是双向进行。 (1) SELECT * FROM .. WHERE expire_unix_time > UNIX_TIMESTAMP();防止读取无效项目和 (2) 每 n 分钟使用一次 EVENT 进行垃圾收集。
【解决方案2】:

可以创建一个视图,如下所示:

create view v_table as
    select (case when unix_time < UNIX_TIMESTAMP() then id end) as id,
           (case when unix_time < UNIX_TIMESTAMP() then user_id end) as user_id
    from banned;

或者:

create view v_table as
    select b.* 
    from banned b
    where unixtime < UNIX_TIME();

这在时间戳之后不会返回有关用户的信息。然后,您可以安排一个事件来定期删除具有过期信息的行。

【讨论】:

  • 在您的查询中始终选择banned 表的所有行。因为对于所有行,您的条件始终为 true unix_time &lt; UNIX_TIMESTAMP()。我应该添加一个名为life_time 的新列,其中包含行的生命周期。那么这里是条件:unix_time &gt; UNIX_TIMESTAMP() - life_time。无论如何谢谢你.. 赞成
  • @stack 。 . .我建议了一个替代方案。
  • 其实我总是害怕使用views。那是因为每次我向视图发送查询时,首先会执行该视图的逻辑,然后再运行我的查询。所以我认为使用view 会产生开销(这确实是对数据库资源的浪费)。但是通过event (每天) 清理桌子需要的过程要少得多。 (清理=删除过期信息)
  • @stack 。 . .这不是视图的工作方式。特别是在这种情况下,视图应该非常有效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-31
  • 1970-01-01
  • 2017-10-27
相关资源
最近更新 更多