2010-09-08 42 views
7

我的应用程序需要轮询MySQL数据库中的新行。每次添加新行时,都应该检索它们。我正在考虑创建一个触发器来将引用放置在一个单独的表上。原始表格有超过300,000行。为新行查询MySQL表的最快方法是什么?

该应用程序使用PHP构建。

一些很好的答案,我认为这个问题值得奖励。

+2

如果可能的话,无论您使用哪个图层插入,即包装CRUD操作的服务,都应在插入后“通知”您的应用程序。这样你不会经常投票。 – Alex 2010-09-08 06:47:20

+0

@Alex:它们是两个不同的独立应用程序。第二个应用程序只能从数据库中读取。 – HyderA 2010-09-08 06:48:12

+1

我会说AFTER INSERT触发器会在现场,在MySQL级别实现,并让脚本轮询和清理另一个表中的新条目。这样,即使强制另一个(非自动增量)ID仍然可以工作。 – Wrikken 2010-09-15 12:26:16

回答

7

因为我发现使用时间戳列外部应用程序是独立的自动识别和其他初级关键问题

将表添加列,如更强大的方法:

insertedOn TIMESTAMP DEFAULT CURRENT_TIMESTAMP 

或跟踪插入和更新

updatedOn TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 

在外部l应用程序所有你需要做的就是当你进行轮询时跟踪最后的时间戳。然后从所有相关表上的该时间戳中进行选择。在大表可能需要索引时间戳列

+0

索引这样的字段将永远*是有益的,不仅在大表格的情况下。无论如何。 – 2010-09-16 20:45:04

+0

索引通常是有益的。当索引开销不值时,有很多用例。通常,在每个基于TIMESTAMP的select和基于TIMESTAMP的select之间进行许多插入和删除的表很少执行 – TFD 2010-09-21 11:03:44

+1

需要注意以下解决方案:如果执行轮询的应用程序正在批处理中进行更改(例如'SELECT * FROM TABLE WHERE updatedOn>:LAST_TIMESTAMP ORDER BY updateOn LIMIT 100'),并且有可能超过批量大小可以一次更新(例如'UPDATE TABLE SET COLUMN ='VALUE'WHERE OTHER_COLUMN ='选择数百个ROWS''),那么你会错过行。 – ICR 2015-08-11 17:02:51

3

您可以使用下面的语句来找出一个新的记录被插入该表:

select max(id) from table_name 

替换上述声明的主键和表名的名称。将max(id)值保留在一个临时变量中,并检索此值与上次保存的最大(id)值之间的所有新记录。获取新记录后,将max(id)值设置为您从查询中获得的值。

+1

为什么不选择* from table_name where id>:max – 2010-09-19 08:58:39

0

假设你有一个标识或者是始终种植一些其他的数据,你应该跟踪上检索到的最后一个ID的PHP应用程序。

适用于大多数场景。除非你进入真正的时间阵营,否则我不认为你会需要更多。

0

我会做这样的事情。当然,这是假定ID是一个递增的数字ID。 以及如何将您的“当前位置”存储在数据库中取决于您。

<? 
$idFile = 'lastID.dat'; 

if(is_file($idFile)){ 
    $lastSelectedId = (int)file_get_contents($idFile); 
} else { 
    $lastSelectedId = 0; 
} 

$res = mysql_query("select * from table_name where id > {$lastSelectedId}"); 

while($row = mysql_fetch_assoc($res)){ 
    // Do something with the new rows 

    if($row['id']>$lastSelectedId){ 
     $lastSelectedId = $row['id']; 
    } 
} 

file_put_contents($idFile,$lastSelectedId); 

?> 
0

我会TFD的关于保持在一个单独的文件/表来跟踪一个时间戳,然后取比新的所有行的答案concurr。这就是我为类似的应用程序做的。

您的应用程序查询单行表(或文件),看是否有时间戳已经从本地存储改变应该不会有太大影响性能的。然后,根据时间戳从300k行表中提取新行应该没问题,假设时间戳已正确编制索引。

然而,读您的问题,我很好奇,如果MySQL触发器可以做系统调用,说一个PHP脚本,会做一些繁重的。通过使用sys_exec()User-Defined Function原来they can。您可以使用它通过将插入的行数据传入进行各种处理,基本上可以立即通知插入。

最后,a word of caution关于使用触发器调用外部应用程序。

0

一个选项可能是使用INSERT INTO SELECT语句。从使用时间戳拉最新行的建议服用,你可以不喜欢......

INSERT INTO t2 (
    SELECT * 
    FROM t1 
    WHERE createdts > DATE_SUB(NOW(), INTERVAL 1 HOUR) 
); 

这将采取所有插入前一小时的行和表2。你可以让它们插入一个脚本运行这个查询并让它每小时运行一次(或者任何你需要的时间间隔)。

这将大大简化您的拉动行的PHP脚本,因为您不需要遍历任何行。它也摆脱了必须跟踪最后一个插入ID。

Fanis的解决方案听起来也很有趣。

作为说明,上述插入中的select查询可以调整为只插入某些字段。如果你只需要某些字段,你,需要像这样插入到指定它们...

INSERT INTO t2 (field1, field2) (
    SELECT field1, field2 
    FROM t1 
    WHERE createdts > DATE_SUB(NOW(), INTERVAL 1 HOUR) 
); 
1

创建一个PHP后台程序监视的MySQL表文件的大小,如果大小为新记录查询的变化,如果新发现记录运行下一个过程。

我认为有一个活动的PEAR守护进程可以很容易地配置来监视MySQL表文件大小并启动​​脚本。

+1

我不确定是否需要MySQL,但通常表空间是以块的形式分配的,因此一旦分配完成,可以在需要进行另一次分配之前添加几行。 – pascal 2010-09-21 01:59:50

+0

如果使用innodb,许多表都在同一个文件中。 – frodeborli 2017-03-24 10:19:47

相关问题