php 在PDO中使用持久连接有哪些缺点

x0fgdtte  于 2023-01-24  发布在  PHP
关注(0)|答案(8)|浏览(193)

在PDO中,可以使用PDO::ATTR_PERSISTENT属性使连接持久化。
持久性连接不会在脚本结束时关闭,而是在另一个脚本使用相同身份证明请求连接时进行高速缓存并重新使用。持久性连接高速缓存使您可以避免每次脚本需要与数据库通信时都建立新连接的开销,从而提高Web应用程序的速度。
手册还建议在使用PDO ODBC驱动程序时不要使用持久连接,因为这可能会妨碍ODBC连接池过程。
因此,除了最后一种情况外,在PDO中使用持久连接似乎没有任何缺点,但我想知道使用这种机制是否还有其他缺点,即这种机制会导致性能下降或类似情况。

qxsslcnc

qxsslcnc1#

请务必阅读this answer below,其中详细介绍了缓解此处所述问题的方法。
使用PDO与使用任何其他进行持久连接的PHP数据库接口存在相同的缺点:如果脚本在数据库操作过程中意外终止,则获得剩余连接的下一个请求将从失效脚本停止的地方继续。连接在进程管理器级别保持打开状态(Apache的mod_php,如果你使用FastCGI,当前的FastCGI进程,等等),而不是在PHP级别,并且PHP不会告诉父进程在脚本异常终止时让连接终止。
如果失效脚本锁定了表,则这些表将保持锁定状态,直到连接失效或获取连接的下一个脚本自行解锁表。
如果死脚本处于事务中间,则可能阻塞大量表,直到死锁计时器开始计时,即使这样,死锁计时器也可能终止较新的请求,而不是导致问题的较旧的请求。
如果死脚本在事务的中间,那么获得该连接的下一个脚本也会获得事务状态。很有可能(取决于应用程序设计)下一个脚本实际上从未尝试提交现有事务,或者在不应该提交时提交,或者在不应该提交时回滚。
这仅仅是冰山一角。在每次脚本请求时,总是尝试在脏连接后进行清理,可以在一定程度上缓解这一问题,但根据数据库的不同,这可能会很痛苦。除非您已将创建数据库连接确定为脚本中的“瓶颈”(这意味着您已经使用xdebug和/或xhprof进行了代码分析),您不应该将持久连接视为任何问题的解决方案。
此外,大多数现代数据库(包括PostgreSQL)都有自己的首选连接池执行方式,这些方式没有普通的基于PHP的持久连接所具有的直接缺点。
为了澄清一点,我们在我的工作场所使用持久连接,但不是出于选择。我们遇到了“奇怪”的连接行为,从应用程序服务器到数据库服务器的初始连接“正好”花了三秒,而这应该只需要几分之一秒的时间。我们认为这是一个内核错误。我们放弃了尝试排除故障,因为它是随机发生的,不能按需复制,而且我们的外包IT没有具体的能力来跟踪它。
无论如何,当仓库里的人正在处理几百个进来的零件时,每个零件需要3.5秒,而不是半秒,我们必须在他们绑架我们并让我们帮助他们之前采取行动。我们在我们自己开发的ERP/CRM/CMS怪物中打开了一些小部件,亲身体验了持久连接的所有恐怖。追踪所有看似随机发生的微妙小问题和怪异行为。结果发现,那些每周一次的致命错误--我们的用户努力从我们的应用程序中挤出的错误--留下了锁定的表、放弃的交易和其他不幸的不稳定状态。
这个悲伤的故事有一个道理:**它以性能的名义破坏了我们从未预料到的东西。**这种代价是不值得的,我们急切地等待着有一天我们可以切换回正常的连接,而不会引起用户的骚动。

dy1byipe

dy1byipe2#

响应于查尔斯的上述问题,
出发地:http://www.php.net/manual/en/mysqli.quickstart.connections.php-
对于持久连接的一个常见抱怨是,在重用之前,它们的状态不会重置。例如,打开和未完成的事务不会自动回滚。而且,在将连接放入池和重用连接之间发生的授权更改也不会得到反映。这可能被视为不希望的副作用。相反,名称“持久”可被理解为状态被持久化的承诺。
mysqli扩展支持持久连接的两种解释:状态持久化,状态在重用之前重置。默认值为重置。在重用持久连接之前,mysqli扩展隐式调用mysqli_change_user()以重置状态。持久连接对用户来说就像刚打开一样。以前使用的任何工件都不可见。
mysqli_change_user()函数是一个开销很大的操作。为了获得最佳性能,用户可能希望设置编译标志MYSQLI_NO_CHANGE_USER_ON_PCONNECT来重新编译扩展。
用户可以在安全行为和最佳性能之间进行选择。这两种行为都是有效的优化目标。为了便于使用,安全行为被设置为默认行为,但牺牲了最佳性能。

5tmbdcev

5tmbdcev3#

只有在连接到数据库需要花费(相对)长时间的情况下,持久连接才是一个好主意。如今,这种情况几乎不存在。持久连接最大的缺点是它限制了浏览网站的用户数量:如果MySQL被配置为一次只允许10个并发连接,那么当第11个人试图浏览您的站点时,它将对他们无效。
PDO不管理持久性。MySQL驱动程序管理。它在以下情况下重用连接:a)连接可用,并且主机/用户/密码/数据库匹配。如果有任何更改,它将不会重用连接。最好的情况是,这些连接将频繁地启动和停止,因为您在网站上有不同的用户,使它们持久化并没有任何好处。
了解持久连接的关键是你不应该在大多数网络应用程序中使用它们。它们听起来很诱人,但它们很危险,而且几乎毫无用处。
我确信还有其他线程在处理这个问题,但是持久连接是危险的,因为它在请求之间持久存在。您在请求期间锁定了一个表,然后解锁失败,则该表将无限期地保持锁定状态。持久连接对于99%的应用程序来说也几乎毫无用处,因为你无法知道在不同的请求之间是否会使用相同的连接。每个web线程都有自己的一组持久连接,您无法控制哪个线程将处理哪个请求。
PHP的过程式mysql库,有一个特性,即对mysql_connect的后续调用将返回相同的链接,而不是打开一个不同的连接(正如人们所期望的)。这与持久连接无关,是mysql库特有的。PDO没有表现出这样的行为
资源链接:链接
一般情况下,您可以将其用作粗略的“规则集”:

  • 是 *,使用持久连接,如果:
  • 只有很少的应用程序/用户访问数据库,也就是说,您不会导致200个打开的(但可能是空闲的)连接,因为在同一台主机上共享了200个不同的用户。
  • 数据库正在您通过网络访问的另一台服务器上运行
  • 一个应用程序经常访问数据库
  • 否 *,不使用持久连接,如果:
  • 您的应用程序每小时只需要访问数据库100次。
  • 您有许多Web服务器访问一个数据库服务器

使用持久连接的速度要快得多,特别是在通过网络访问数据库时。如果数据库运行在同一台机器上,这不会有太大区别,但它仍然快一点。然而,正如名称所示,连接是持久的,即即使不使用它,它也会保持打开状态。
这样做的问题是,在“默认配置”中,MySQL只允许1000个并行的“开放通道”,超过这一数目,新的连接将被拒绝(你可以调整这个设置)。所以如果你有--比如说-- 20个Web服务器,每100个客户端在它们上面,并且每一个服务器每小时只有一个页面访问,简单的数学计算会告诉你,你需要2000个并行连接到数据库,这是行不通的。

  • 因此:仅将其用于请求较多的应用程序。*
eulz3vhy

eulz3vhy4#

在我的测试中,我连接到本地主机的时间超过了一秒,因此我假设我应该使用持久连接。进一步的测试表明这是'localhost'的问题:
测试结果(秒)(由php microtime测量):

  • 托管网站:连接数据库:0.0038912296295166
  • 本地主机:连接数据库:1.0214691162109(超过一秒:不要使用本地主机!)
  • 127.0.0.1:连接数据库:0.00097203254699707

有趣的是:下面的代码与使用www.example.com一样快127.0.0.1:

$host = gethostbyname('localhost');
// echo "<p>$host</p>";
$db = new PDO("mysql:host=$host;dbname=" . DATABASE . ';charset=utf8', $username, $password,
    array(PDO::ATTR_EMULATE_PREPARES => false,
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
velaa5lx

velaa5lx5#

持久连接应该会给性能带来相当大的提升。我不同意你应该“避免”持久性的说法。
听起来上面的抱怨是由一些人使用MyIASM表并通过获取表锁来攻击他们自己版本的事务引起的。当然,你会死锁!使用PDO的beginTransaction()并将你的表移动到InnoDB。

h22fl7wq

h22fl7wq6#

在我看来,有一个持久的连接会消耗更多的系统资源。也许是微不足道的数量,但仍然...

p1iqtdky

p1iqtdky7#

对使用持久连接的解释显然是减少了连接的数量,尽管事实上与其他数据库相比,MySQL的连接速度要快得多。
持久连接的第一个问题是...
如果您每秒创建1000个连接,您通常无法确保它长时间保持打开状态,但操作系统可以。基于TCP/IP协议,端口不能立即回收,而且必须在“FIN”阶段投入一段时间等待,然后才能回收。
第二个问题...使用了大量的MySQL服务器连接。
许多人根本没有意识到你能够增加 max_connections 变量,并获得超过100个与MySQL的并发连接,其他人则被旧的Linux问题击败,无法传递超过1024个与MySQL的连接。
允许谈论为什么持久连接在mysqli扩展中被禁用。尽管事实上你可以滥用持久连接并获得糟糕的性能,这不是主要原因。实际原因是-你可以得到更多的问题。
持久连接在MySQL 3.22/3.23的时候就已经被放入PHP中了,这意味着你可以很容易地回收连接而不会有任何问题。但是在后来的版本中,大量的问题出现了--如果你回收的连接有未提交的事务,你会有麻烦。如果你回收的连接有自定义的字符集配置,你会再次处于危险之中。以及关于可能变换的每个会话变量。
使用持久连接的一个问题是它不能很好地扩展。对于那些有5000人连接的人,你需要5000个持久连接。为了消除持久性的要求,你可能有能力用类似数量的连接服务10000人,因为他们在不与他们共享个人连接时处于一个位置。

bnlyeluc

bnlyeluc8#

我只是想知道是否有一个部分解决方案是拥有一个一次性使用的连接池,当系统使用率低时,您可以花时间创建一个连接池,分发它们,并在它们完成或超时时杀死它们。在后台,当它们被获取时,您将创建新的连接。在最坏的情况下,假设建立链路是限制因素,这应该只会像创建没有池的连接一样慢。

相关问题