在PHP中,file_exist()是否是一项非常昂贵的操作?

18

我正在设计一个论坛引擎,并为其添加头像功能。目前正在考虑两种方案:一是使用简单方法(将论坛图像命名为.png文件),在显示之前使用PHP检查文件是否存在;二是使用稍微复杂一些的方法(但并不太复杂),使用数据库字段来存储图片名称。

我个人更倾向于使用file_exists()方法,因为这可以让我轻松地回到“默认”头像,如果当前的头像不存在(尚未上传),那么实现代码也很简单。然而,我担心性能问题,因为每次加载页面时,论坛读取页会对每个用户都运行一次该程序。所以我想知道,PHP中的file_exists()函数是否会导致任何主要的减速,在高流量情况下会有显著的性能影响吗?

如果没有,那就太好了。如果有,您对于跟踪用户上传图像的替代方案有何意见?谢谢!

附注:根据我看到的代码差异,文件检查版本让文件自己说话,而数据库则相信数据库的准确性,不费心检查。(当然只是将url传递给浏览器)

7个回答

12

除了其他海报已经说的,file_exists()函数的结果会被PHP自动缓存以提高性能。

然而,如果您已经从数据库中读取用户信息,那么最好将信息存储在其中。 如果用户只允许一个头像,您可以在“是否有头像”(1/0)的列中仅存储一个位,然后文件名与用户ID相同,并使用类似 SELECT CONCAT(IF(has_avatar, id, 'default'), '.png') AS avatar FROM users 的东西。

您还可以考虑将实际图像作为BLOB存储在数据库中。 将其放置在自己的表中,而不是作为列连接到用户表。 这样的好处是使您的论坛非常容易备份-您只需导出数据库即可。


缓存信息非常令人放心,最终我选择了file_exists解决方案。然而,BLOB的想法看起来非常有趣,我以后可能会尝试一下。谢谢! - Blank
6
但是BLOB不利于性能。你会增加PHP、MySQL的负担,并且你需要编写HTTP缓存验证的支持,否则浏览器会不必要地一遍又一遍地重新下载头像。 - Kornel
4
需要翻译的内容:重要的是要注意,PHP只会缓存已存在文件的结果,不会缓存不存在文件的结果。参见:http://www.php.net/manual/en/function.clearstatcache.php - Brian

8

由于您的Web服务器在显示网页的过程中已经完成了许多(相当于)file_exists()操作,因此您的脚本再运行一次可能不会有明显的影响。Web服务器可能会至少执行以下操作:

  • 每个Web根目录的子目录都要进行一次(用于检查存在性和符号链接)
  • 每个Web根目录的子目录都要检查一个.htaccess文件
  • 检查您的脚本是否存在

这还没有考虑PHP本身可能执行的更多操作。


8
在实际的性能测试中,你会发现file_exists非常快。在php中,当相同的url被“stat”两次时,第二个调用只是从php的内部stat缓存中获取。而且这仅限于php运行环境范围内。即使在多次运行之间,文件系统/操作系统也会倾向于将文件积极地放入文件系统缓存中,如果文件足够小,则不仅文件存在测试可以直接从内存中读取,整个文件也可以从内存中读取。
以下是一些真实数据来支持我的理论:
我刚刚对Linux命令行实用程序“find”和“xargs”进行了一些性能测试。在过程中,我对13000个文件进行了100次文件存在测试,用时不到30秒,因此平均每秒处理43000个stat测试。所以,在精细的尺度上,如果与除以8的9的时间进行比较,那么它就很慢了,但在实际情况下,您需要做很多次才能看到明显的性能问题。
如果有43,000个用户同时访问您的页面,那么在一秒钟内,您可能会有比复制文件存在状态的时间更大的问题。

2
至少在PHP4中,我发现调用file_exists绝对会导致我们的应用程序崩溃 - 它在库中被重复调用,因此我们真的必须使用分析器才能找到它。删除这个调用可以将某些页面的计算增加十几倍(该调用非常重复)。
可能在PHP5中他们缓存了file_exists,但至少在PHP4中并非如此。
现在,如果您不在循环中,显然,file_exists就不是什么大问题了。

0

file_exists() 本身并不慢。真正的问题在于您的系统配置以及性能瓶颈所在的位置。请记住,数据库也必须将数据存储在磁盘上,因此无论如何,您都可能面临磁盘活动。另一方面,数据库和文件系统通常都具有某种形式的透明缓存来优化重复访问。

您可以轻松地选择任何一种方式,因为很有可能您的性能瓶颈在其他地方。我唯一能看到它成为明显选择的地方是,如果您正在使用某种超售共享主机,在那里存在大量磁盘争用,但是也许数据库访问在单独的集群上并且更快(或反之亦然)。


0

过去,我将图像元数据(包括其名称)存储在数据库中,以便我们可以生成有用的统计信息。更重要的是,存储图像数据(不是文件本身,只是元数据)有利于变更。如果将来需要“批准”图像,或者您想要删除它而不删除文件怎么办?

至于“默认”头像... 如果找不到该用户的记录,只需使用默认头像即可。

无论是file_exists()还是db,都不应该成为值得担忧的瓶颈。然而,其中一种解决方案更具可扩展性。


你被踩了,我不确定为什么,因为这是一个好答案,而且我自己也没有想到。 - Blank
我不能在正确的答案中发表评论,但还有一件事——不要将图像存储为BLOB。这会导致非常糟糕的性能。相信我,在整个网络上已经讨论了无数次。 - Kevin Dente

0

如果性能是您唯一考虑的因素,那么file_exists()将比数据库查找要便宜得多。

毕竟,这只是使用系统调用进行的目录查找。在脚本的第一次执行之后,大部分相关目录将被缓存在存储器中,因此实际的I/O非常少,并且“file_exists()”是如此常见的操作,以至于在任何常见的php/os组合上都会高度优化它和底层系统调用。

正如John II所指出的那样。如果额外的功能和用户界面特性是优先考虑的,则应选择数据库。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接