如何摆脱MySQL错误'准备好的声明需要重新准备'

时间:2010-12-07 19:36:32

标签: php mysql

我重写了我的网站php-code并添加了MySQL存储过程。

在我的本地版本中一切正常但在我将我的网站上传到托管服务器之后我一直在致命的错误'准备好的声明需要重新准备'。

有时页面加载,有时加载失败,我看到这个错误。那是什么?

更新: 移至VPS服务器后问题已解决。谢谢你的帮助。

10 个答案:

答案 0 :(得分:21)

这是一种可能性:MySQL bug #42041

他们建议提高table_definition_cache的价值。

您可以阅读有关重新准备in the MySQL docs的信息。

答案 1 :(得分:8)

@docwhat's回答看起来不错,但在共享托管服务器上,并非所有人都可以触摸table_open_cachetable_definition_cache选项。

由于此错误与预准备语句有关,因此我尝试通过提供以下选项来“模拟”具有PDO的错误:

$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass, [
    PDO::ATTR_EMULATE_PREPARES => true
]);

注意:实际上这是在Laravel 5.6项目中,我在config/database.php中添加了选项:

'connections' => [
    'mysql' => [
        'driver' => 'mysql',
        'host' => env('DB_HOST', '127.0.0.1'),
        'port' => env('DB_PORT', '3306'),
        'database' => env('DB_DATABASE', 'forge'),
        'username' => env('DB_USERNAME', 'forge'),
        'password' => env('DB_PASSWORD', ''),
        'unix_socket' => env('DB_SOCKET', ''),
        'charset' => 'utf8mb4',
        'collation' => 'utf8mb4_unicode_ci',
        'prefix' => '',
        'strict' => true,
        'engine' => null,
        'options' => [
            PDO::ATTR_EMULATE_PREPARES => true,
        ],
    ],
    (...)
],

我没有测试模拟预处理语句对加载我的网站的持续时间的影响,但它对我得到的错误SQLSTATE[HY000]: General error: 1615 Prepared statement needs to be re-prepared起作用。

关于性能的

更新:模拟版本似乎略微更快(模拟32.7±1.4ms,正常35.0±2.3ms,n = 10,p值对于双尾学生T检验,= 0.027。

答案 2 :(得分:3)

简而言之:不要在准备好的语句中使用VIEWS。

这似乎是一个持续的问题

使用动态SQL处理视图很麻烦

最早的错误是Cannot create VIEWs in prepared statements from 11 years ago. There was a patch put in to address it.

另一个错误报告Prepared-Statement fails when MySQL-Server under load指出,当基础表繁忙时,错误1615并不是错误。 (真的吗?)

虽然增加表缓存大小有一些好处(请参见MySql error when working with a mysql view), it does not always work (See General error: 1615 Prepared statement needs to be re-prepared (selecting mysql view)

替代品 一年多以前,有人在MySQL Forum (MySql “view”, “prepared statement” and “Prepared statement needs to be re-prepared”)中提到了这一点。

有人提出the simple idea of not using the view in the prepared statement but using the SQL of view in a subquery instead。另一个想法是去create the SQL used by the view and execute it in your client code

这些似乎是更好的解决方法,只是增加了表缓存的大小。

答案 3 :(得分:2)

问题:“准备好的声明需要重新准备”

此问题通常发生在通过使用任何计算机语言(如Java)或从后端调用过程来调用过程时。

解决方案:通过使用(执行)以下脚本来增加缓存的大小。

脚本:设置全局table_definition_cache = 4000;

答案 4 :(得分:1)

我的解决方案是创建一个这样的例程:

DELIMITER $$
--
-- Procedimientos
--
DROP PROCEDURE IF EXISTS `dch_content_class_content`$$

CREATE DEFINER=`renuecod`@`localhost` PROCEDURE `dch_content_class_content`(IN $classId INTEGER)
BEGIN
-- vw_content_class_contents is a VIEW (UNIONS)
  select * from vw_content_class_contents;
END$$

我希望这有助于某人

答案 5 :(得分:1)

首先获得对 mysql shell 的访问权限:

mysql 

检查 table_definition_cache 的值:

show global variables like '%table_definition_cache%';

可能是 400 或 1400。

放大:

set global table_definition_cache = 4000;

好!

答案 6 :(得分:0)

这是一种解决方法,适用于共享主机上的用户,不想冒险使用sql注入。根据这篇文章: Laravel Fluent Query Builder Join with subquery 您可以将视图的定义存储在函数中

private function myView(){
    return DB::raw('(**definition of the view**) my_view_name)');
}

然后像这样使用它:

public function scopeMyTable(Builder $query)
{
    return $query->join($this->myView(),'my_view_name.id','=','some_table.id');
}

这是一种laravel方法,但是我确信它可以在大多数情况下应用,并且不需要大量的代码重构或体系结构更改。另外,由于您的陈述保持准备状态,因此相对安全

答案 7 :(得分:0)

冲洗表;数据库上的命令为我解决了,我使用的是学说 orm。

答案 8 :(得分:0)

这个错误是由一个大的 group_concat_max_len 语句引起的 SET SESSION group_concat_max_len = 1000000000000000000; 删除它,错误消失了

答案 9 :(得分:-1)

我在共享托管环境中的Ruby on Rails中遇到了同样的错误。它可能不是最安全的解决方案,但是禁用预处理语句可以解决我的错误消息。

这可以通过添加" prepared_statements:false"设置为database.yml文件:

production:
  prepared_statements: false

当您无法控制MySQL服务器上的配置设置时,这似乎是一个合理的解决方案。

相关问题