通过PHP登录到文件或登录到MySQL数据库-这会更快


Log to file via PHP or log to MySQL database - which is quicker?

我有一个数据库驱动的网站,提供大约50000个页面。

我想跟踪每一个网页/记录点击。我将通过创建日志来实现这一点,然后每天批处理一次日志。我不关心如何进行批量处理,只关心最快的登录方式。

你会如何登录,你认为哪个更快:

a) 使用PHP将其附加到文本日志文件的末尾。

b) 使用MySQL将非索引日志表插入。

  1. 写入文件。旋转原木。

  2. 将文件批量加载到数据库在预定的基础上。

选择这种体系结构有很多原因——易于扩展(写入许多日志,加载到数据库),不依赖数据库中的SPOF(如果出现问题,只需积累一段时间的日志),能够在加载时进行清理和非琐碎的解析,而不会给生产服务器带来负担,等等。

您可以使用log4php尝试两种方法,它支持:

  • 通过xml和属性文件进行配置(结构与log4j相同)
  • File、RollingFile、DailyFile、Echo、Console、Mail、PEAR::Db、PHP错误、Syslog或NT事件以及Socket附加程序
  • Simple、TTCC、Pattern、Html和Xml布局
  • 嵌套(NDC)和映射(MDC)诊断上下文
  • 可切换的内部调试

关于登录到文件,可以通过缓冲写请求来提高性能。

我会使用延迟插入MySQL。这样,您就不必等待插入完成。

使用数据库-这是唯一合理的选择。即使需要更长的时间。一旦你开始使用日志文件,那么你就陷入了一个会给你带来痛苦的轨道上——例如,移动服务器、文件权限、排除负载平衡等

如果你打开了数据库,那么我认为插入一行可能会更快。

然而,与所有这些性能相关的唯一方法是编写一个简单的测试并测量它…

更新:我已经做了一个快速测试,如果你必须打开和关闭文件,使用10000行的测试速度大致相同或更慢:

然而,当您开始让多个进程执行此操作时,速度会减慢,如下所示。这是10个并发进程(所有时间以秒为单位)

DB time: 2.1695
DB time: 2.3869
DB time: 2.4305
DB time: 2.5864
DB time: 2.7465
DB time: 3.0182
DB time: 3.1451
DB time: 3.3298
DB time: 3.4483
DB time: 3.7812
File open time: 0.1538
File open time: 0.5478
File open time: 0.7252
File open time: 3.0453
File open time: 4.2661
File open time: 4.4247
File open time: 4.5484
File open time: 4.6319
File open time: 4.6501
File open time: 4.6646
Open close file time: 11.3647
Open close file time: 12.2849
Open close file time: 18.4093
Open close file time: 18.4202
Open close file time: 21.2621
Open close file time: 22.7267
Open close file time: 23.4597
Open close file time: 25.6293
Open close file time: 26.1119
Open close file time: 29.1471
function debug($d)
{
    static $start_time = NULL;
    static $start_code_line = 0;
    if( $start_time === NULL )
    {
        $start_time = time() + microtime();
        $start_code_line = $code_line;
        return 0;
    }
    printf("$d time: %.4f'n", (time() + microtime() - $start_time));
    $fp = @fopen('dbg.txt','a');
    fprintf($fp,"$d time: %.4f'n", (time() + microtime() - $start_time));
    fclose($fp);
    $start_time = time() + microtime();
    $start_code_line = $code_line;
}
function tfile()
{
    $fp = @fopen('t1.txt','a');
    for ($i=0;$i<10000;$i++)
    {
        $txt = $i."How would you log, which do you think is quicker:How would you log, which do you think is quicker:";
        fwrite($fp,$txt);
    }
    fclose($fp);
}
function tfile_openclose()
{
    for ($i=0;$i<10000;$i++)
    {
        $fp = @fopen('t1.txt','a');
        $txt = $i."How would you log, which do you think is quicker:How would you log, which do you think is quicker:";
        fwrite($fp,$txt);
        fclose($fp);
    }
}
function tdb()
{
    $db = mysql_connect('localhost','tremweb','zzxxcc');
    $select_db = mysql_select_db('scratch');
    if (!$select_db) 
        die('Error selecting database.');
    for ($i=0;$i<10000;$i++)
    {
        $txt = $i."How would you log, which do you think is quicker:How would you log, which do you think is quicker:";
        mysql_query("INSERT INTO tlog values('".$txt."')");
    }
}
debug("");
tfile();
debug("File open");
tfile_openclose();
debug("Open close file");
tdb();
debug("DB");

我相信平面文件写入速度会更快。它将为您提供写入文件的速度以及数据库的功能。

  • php.net:sqlite2扩展
  • php.net:sqlite3类
  • pdo提供了一个SQLite驱动程序

几年前,我在《C++用户杂志》上读到一篇关于loggin性能的文章。无论您使用DB还是文件,最好的方法是在需要查看日志时(更有可能)写入未格式化的数据,这些数据可以"膨胀"为有意义的数据。日志记录的绝大多数成本是为写入目标的字符串提供信息,而这些成本的大部分时间都被浪费了——日志永远不会被读取。

如果这篇文章对你有用的话,我可以把它挖出来。

我建议您使用一些测试用例来测试这两种情况。

我认为平面文件会更快,b/c这正是DB正在做的事情——它只是将它写入一个文件。我能想到的唯一优点是,如果数据库可以并发运行,您可能会得到更好的结果。

我也做过类似的事情。我将每条记录记录记录到一个单独的文件中,然后我有一个批处理过程来获取文件,将它们放入一个tar文件中,并将它们上传到中央日志服务器(在我的例子中,S3:))。

我为每个日志条目生成随机文件名。我这样做是为了避免锁定文件进行旋转。用这种方式归档/删除真的很容易。

我使用json作为日志格式,而不是典型的以空格分隔的日志文件。这使得将来更容易解析和添加字段。这也意味着,对我来说,每个文件写一个条目比每个文件附加多个记录更容易。

我还使用了log4hp+syslog-ng来实时集中日志记录。我有一个到syslog的log4php日志,然后它将这些日志转发到我的中央服务器。这对较大的集群非常有用。需要注意的是,系统日志消息有长度限制,因此较长的消息可能会被截断。

如果您使用基于文件的日志记录或基于数据库的日志记录,那么最大的性能打击将是文件/表锁定。基本上,如果客户端A和客户端B在相对较小的时间范围内连接,则客户端B会被卡住,等待命中文件/表的锁定释放,然后再继续。

基于文件的机制的问题在于,文件锁定对于确保您的点击不会被破坏至关重要。唯一的解决方法是实现一个队列来延迟写入文件。

使用数据库日志记录,您至少可以执行以下操作[MySQLusingMyISAM]:

INSERT DELAYED INTO `hits` ...

见12.2.5.2。有关详细信息,请参阅INSERT DELAYED语法。

进入文件会更快,但进入数据库会更好。

这一切都取决于您的基础设施和限制。如果磁盘速度较慢,则写入速度将较慢。如果SQL服务器因请求而滞后,则插入速度将很慢。平面文件可能是最好的方法,但我会编写您的代码或使用现有代码(PEAR::Log),这样您就可以随意更改提供程序和存储方法。

几个注意事项:

  1. 您认为要将日志数据与数据库中的其他数据连接起来吗?如果是这样的话,数据库插入的开销可能是合理的,这样就可以很容易地利用现有的关系
  2. 将数据记录到数据库中是否可以大大减少记录的数据量(由于数据库中存在关系)?例如,用户活动数据库中的日志可以只是一个包含userid、activityid和时间戳的表。这样精简的日志文件是不可读的。根据您的需要,您需要在日志文件中捕获至少一些用户的数据,以确保它本身是有用的和可读的
  3. 你有没有可能想在前端或通过管理工具利用这些日志数据?如果是这样,DB写入可能更可取

正如其他人所提到的,这取决于很多因素,如流量、磁盘速度等。您必须测试这两种场景。

在测试MySQL时,请同时尝试MyISAM和INNODB。理论上,Innodb的性能会更好,因为它具有行级锁定。

如果这是一个数据库驱动的网站,为什么不使用Apache或IIS的内置日志记录功能,以及适当的报告工具,如AWStats等,除此之外,总有谷歌分析

AWStats和Web服务器日志记录是我的首选-无论如何,你基本上都可以免费获得它-即使你没有完成流量分析,你仍然可以考虑自己解析Apache访问日志文件,以进行任何需要进行的批处理