PHP最快的方式是在MYSQL中注册数百万条记录

时间:2016-02-12 09:53:54

标签: php mysql performance

我必须在我的数据库中注册数百万的页面浏览量,我正在寻找降低服务器负载的最佳解决方案。

1。实际解决方案:检查是否唯一,并在“原始”表和“优化”表中注册

// script
$checkUnique = mysqli_query( $con, "SELECT FROM rawTable
         WHERE datatime = '$today' AND ip = '$ip'
         ORDER BY datetime DESC LIMIT 1" );
mysqli_query( $con, "INSERT INTO rawTable ( id, datetime, url, ip, ua )
         VALUES ( NULL, '$now', '$url', '$ip', '$ua' )" );
if( mysqli_num_rows( $checkUnique ) == 0 ) {
    mysqli_query( $con, "INSERT INTO optimizedTable ( id, day, total )
                         VALUES ( NULL, '$today', 1 )" ); }
else{
    mysqli_query( $con, "UPDATE optimizedTable SET total = total + 1
            WHERE day = '$today' ORDER BY day DESC LIMIT 1"; }

2。仅在“原始”表中注册视图,然后使用cronjob填充“优化”表

// script
mysqli_query( $con, "INSERT INTO rawTable ( id, datetime, url, ip, ua, alreadyOptimized )
         VALUES ( NULL, '$now', '$url', '$ip', '$ua', 0 )" );

// cronjob -> check if is unique, populate mysql tables +
//         change column alreadyOptimized from 0 to 1 in raw table

第3。在txt或csv文件中注册原始视图,然后使用cronjob填充mysql表

// script
$file = fopen("file.txt", "w");
fwrite($file, "$now,$url,$ip,$ua\n");

// cronjob -> check if is unique, populate mysql tables + delete rows from txt/csv file

什么是最好(最轻和最快)的方式?有没有更好的解决方案?

PS:服务器负载是由select查询引起的,用于检查视图是否唯一

2 个答案:

答案 0 :(得分:9)

手动选择检查记录是否存在是您可以做的最糟糕的事情 - 它可以(并且会)产生错误的结果。 MySQL与连接它的任何进程之间存在时间差。唯一正确的方法是放置UNIQUE约束,只是INSERT。这是100%确定您的数据库不会包含重复项的唯一方法。

这对您的用例感兴趣的原因是它将您的代码减少了50%。您不必先SELECT,因此您摆脱了巨大的瓶颈。

如果您需要更新现有记录,请使用INSERT IGNOREINSERT INTO .. ON DUPLICATE KEY UPDATE

您的唯一约束是datetime, ip列上的复合索引。要进一步优化此功能,您可以在表格中创建binary(20)列,并使其包含sha1哈希datetime, ip组合。使用触发器,您可以在插入之前创建哈希,使整个过程对插入表中的实际人员不可见。

如果插入失败,则记录存在。如果插入成功,那么你已经完成了你想做的事情。不使用SELECT应该会产生性能。之后,如果它仍然很慢 - 它只是您使用的服务器的I / O限制,您需要在硬件级别上寻找优化。

答案 1 :(得分:1)

目前给出的答案都没有接近“最快”。

IODKU(INSERT .. ON DUPLICATE KEY UPDATE ..)取代了给出的所有步骤。但是,目前还不清楚PRIMARY KEY应该是什么。一些提示“日期”+ IP,一些提示“日期时间”+ IP。但是如果用户使用来自同一IP的两个不同的浏览器($ ua)呢?或者来自不同的页面($ url)?

将数据块化以避免系统影响。也就是说,一次处理一行。并且一次在桌子上扔掉一百万行。前者是sloooow - 通常是某种形式的批处理速度的十倍。后者将对目标表产生严重影响。

如果您突然有一百万行要插入/递增的值,请对其进行预处理。也就是说,在更新实际数据之前,将其简化为每个唯一键的计数。这减少了对真实桌面的影响,尽管它可能会产生一些整体的“系统”影响。但是,此外,将数据块 - 一次说1000行 - 复制到真实表中。 More on Chunking

如果每个 second 中有数百或数千(但不是数百万)个'行',那么有几个选项。首先,它们都来自单一来源吗?或者他们来自多个客户?

从单一来源 - 收集一千行,合并它们,然后构建一个IODKU来完成它们。 (注意如何使用VALUES伪函数。)

从多个来源 - 乒乓球一对桌子。从所有客户端收集一个表中的原始信息。另一个线程处理另一个表,用于将数据放入真实表中。然后这个线程使用单个原子RENAME TABLE翻转表;客户将忘记它。 More on high speed ingestion

与此同时,你应该至少规范化$ ua,因为它们体积庞大且重复性很强。最后一个链接显示了有效批量规范化的2-sql方法。

另一个注意事项:目标表应该具有IODKU的“唯一”键PRIMARY KEY。如果您目前有AUTO_INCREMENT,请将其移至INDEX而不是PRIMARY KEY。 (是的,这确实有效。)理由是通过不通过辅助密钥而不需要第二个UPDATE密钥来检查IODKU的UNIQUE部分。