繁体   English   中英

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

[英]PHP fastest way to register millions of records in MYSQL

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

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查询引起的,用于检查视图是否唯一

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

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

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

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

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

迄今为止给出的答案都没有接近“最快”。

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

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

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

如果你有“行”来在每秒数百或数千(而不是数百万),则有几个选项。 首先,它们都来自单一来源吗? 或者他们来自多个客户?

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM