在mysql中管理行到期的最佳方法

时间:2013-12-23 13:24:09

标签: mysql performance cron indexing partitioning

应用程序执行以下操作:

  • 将行写入具有唯一ID的表
  • 读取表格并找到唯一ID并输出其他变量(其中包括时间戳)。

问题是:应用程序需要只读取未过期的行,这些行每2分钟到期一次。有几种方法可以实现这一目标:哪种方法性能最佳?

考虑读取过期的行并不重要,因为它会偶尔完成。非过期行的数量总是低于几千,但可能只有几百行。

基于时间戳,cron作业(每分钟运行)(或mysql事件计划)可以是以下之一(或任何其他想法?):

A)添加一个BOL变量来索引表,然后读取WHERE未过期(当然基于boll变量) B)添加一个BOL变量来对表进行分区,然后只读取相关的分区(我是分区的新手,所以我不知道这可能会如何解决) C)读取整个表并删除已过期的每一行,然后将同一行写入另一个表 D)写入时,在两个表中同时写两行,然后在一个表中删除过期的行

OR

E)根​​本不使用cron作业并检查每次读取的时间戳。 (但为什么我会扫描整个表?过期的行对应用程序本身来说基本无用)

编辑1

让我重新解释一下这个问题:

目标是仅在少于2分钟前写入行时检索行的所有列。

该表具有此结构,但可以完全重新定义

transactionID CHAR(8) NOT NULL, 
PRIMARY KEY(transactionID),
details VARCHAR(416),
tel INT(10),
time TIMESTAMP(),
address VARCHAR(60),
town VARCHAR(30),
flat VARCHAR (5),
supplier SMALLINT()

supplier也是外键

索引为transactionID,最终为“status”,这是一个额外的列,数据类型为TO_BE_DEFINED_but_probably_SMALLINT _?()

解决方案1:使用索引列指示行的状态(已过期,活动,已使用)

运行 cron作业以将字段值从1(活动)更改为2(已过期),并且查询将如下所示:

$transaction = //a POST or GET 

$query = mysqli_query($con,"SELECT * FROM table WHERE transaction = '$transaction' AND status = 1");

if(mysql_num_rows($query)== 0){
   echo "Transaction expired";
}
else{
// I will show all the fields in the selected row;
}

mysqli_close($con);

解决方案2:根据每行的时间戳

使用分区

运行 cron作业以实现每2分钟对列进行一次分区,但查询可能更快:

$transaction = //a POST or GET 

$query = mysqli_query($con,"SELECT * FROM table WHERE transaction = '$transaction' AND PARTITION (active)");

if(mysql_num_rows($query)== 0){
   echo "Transaction expired";
}
else{
// I will show all the fields in the selected row;
}

mysqli_close($con);
然后,cron的工作将与此类似

$date = date("Y-m-d H:i:s");
$time = strtotime($date);
$check = $time - (2);


$query = mysqli_query($con,"PARTITION BY RANGE (timestamp_field) 
(PARTITION active VALUES LESS THAN ($check)),
((PARTITION expired VALUES MORE THAN ($check));")

解决方案3:忘记所有这些并将时间戳大于2分钟的行复制到另一个带有cron作业的表

虽然脚本在写入方面可能很重,但是很容易实现,但是对于“过期”表的写入效率是无关紧要的,我希望“活动”查询快速。

解决方案3B:添加行时,也将其写入另一个表,以便它只是一个cron作业必须执行的DELETE函数。

解决方案4:忘记它的所有内容和时间戳上的WHERE

$transaction = //a POST or GET 

$date = date("Y-m-d H:i:s");
$time = strtotime($date);
$check = $time - (2);

$query = mysqli_query($con,"SELECT * FROM table WHERE transaction = '$transaction' AND timestamp > $check");

if(mysql_num_rows($query)== 0){
   echo "Transaction expired";
}
else{
// I will show all the fields in the selected row;
}

mysqli_close($con);

1 个答案:

答案 0 :(得分:14)

您没有提到您正在使用的MySQL版本。只要您拥有5.1,就可以使用事件计划程序

CREATE EVENT clearExpired
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 2 MINUTES
DO
   UPDATE table SET status=0
    WHERE status <> 0
      AND TIMESTAMPDIFF(SECONDS, NOW(),table.timestamp)>120;

CREATE EVENT clearExpired
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 2 MINUTES
DO
   DELETE FROM table
    WHERE TIMESTAMPDIFF(SECONDS, NOW(),table.timestamp)>120;

在这种情况下,您还可以设置一个触发器,将所有已删除的行复制到历史记录表中,然后再删除它们。

为了衡量效率,请创建一个表格 events (列:时间戳和操作),并在表格中生成大量行,然后将您的活动更改为:

...
DO
   BEGIN
      INSERT INTO events SET action="clearExpired start";
      <insert or delete>
      INSERT INTO events SET action="clearExpired end";
   END

然后你可以看到一种方式与另一种方式需要多长时间。

但是,此事件每分钟或每两分钟只运行一次,而且会有更多插入。您希望优化最常发生的操作。