Php MySQL无法保存结果集
这是一个生产PHP/MySQL系统,已经运行了几个月,基本上没有问题 我偶尔会在MySQL查询中看到“无法保存结果集”错误,比如每隔几周就出现一次 我知道这可能是由一个大的结果集引起的,但这里的情况并非如此。在最近的一个例子中,它发生在通常不超过10行的小桌子上(行表示活动的游戏,它们在游戏结束后被移除——翻倍很多,但总是很小) 查询非常简单:Php MySQL无法保存结果集,php,mysql,Php,Mysql,这是一个生产PHP/MySQL系统,已经运行了几个月,基本上没有问题 我偶尔会在MySQL查询中看到“无法保存结果集”错误,比如每隔几周就出现一次 我知道这可能是由一个大的结果集引起的,但这里的情况并非如此。在最近的一个例子中,它发生在通常不超过10行的小桌子上(行表示活动的游戏,它们在游戏结束后被移除——翻倍很多,但总是很小) 查询非常简单: SELECT player_1_id, player_2_id FROM minuetServer_games WHERE ( player_1_i
SELECT player_1_id, player_2_id FROM minuetServer_games
WHERE ( player_1_id = '1513399' OR player_2_id = '1513399' )
AND last_action_time < SUBTIME( CURRENT_TIMESTAMP, '0 0:01:22.000' )
FOR UPDATE;
以下是cm_connectToDatabase的代码:
function cm_connectToDatabase( $inTrackStats = true) {
global $databaseServer,
$databaseUsername, $databasePassword, $databaseName,
$cm_mysqlLink;
$cm_mysqlLink =
mysql_connect( $databaseServer,
$databaseUsername, $databasePassword );
// bunch of error handling if $cm_mysqlLink is false
// ....
}
请注意,“无法保存结果集”是mysql\u查询引发的警告。此外,该查询每天运行数百次,没有问题。此警告最多每隔几周出现一次。以下是几天前的最新堆栈跟踪:
Warning: mysql_query() [<a href='function.mysql-query'>function.mysql-query</a>]: Unable to save result set in /home/jcr14/public_html/gameServer/server.php on line 11248
#0 cm_noticeAndWarningHandler(2, mysql_query() [<a href='function.mysql-query'>function.mysql-query</a>]: Unable to save result set, /home/jcr14/public_html/gameServer/server.php, 11248, Array ([inQueryString] => SELECT player_1_id, player_2_id FROM minuetServer_games WHERE ( player_1_id = '1513399' OR player_2_id = '1513399' ) AND last_action_time < SUBTIME( CURRENT_TIMESTAMP, '0 0:01:22.000' ) FOR UPDATE;,[inDeadlockFatal] => 0,[cm_mysqlLink] => Resource id #4))
#1 mysql_query(SELECT player_1_id, player_2_id FROM minuetServer_games WHERE ( player_1_id = '1513399' OR player_2_id = '1513399' ) AND last_action_time < SUBTIME( CURRENT_TIMESTAMP, '0 0:01:22.000' ) FOR UPDATE;, Resource id #4) called at [/home/jcr14/public_html/gameServer/server.php:11248]
#2 cm_queryDatabase(SELECT player_1_id, player_2_id FROM minuetServer_games WHERE ( player_1_id = '1513399' OR player_2_id = '1513399' ) AND last_action_time < SUBTIME( CURRENT_TIMESTAMP, '0 0:01:22.000' ) FOR UPDATE;, 0) called at [/home/jcr14/public_html/gameServer/server.php:5979]
这也被称为一天100次,没有问题。这是一张只有一行的表
周围的代码:
function cm_getNewSquare() {
global $tableNamePrefix;
// have it wrap around at the 32-bit unsigned max
// because getMagicSquare6 takes a 32-bit unsigned seed.
// we store it as a BIGINT to keep it from getting stuck on the same
// square after four billion games
$query = "SELECT next_magic_square_seed % 4294967296 ".
"FROM $tableNamePrefix".
"server_globals FOR UPDATE;";
$result = cm_queryDatabase( $query );
编辑4:
表格结构:
mysql> describe minuetServer_games;
+-----------------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------+---------------------+------+-----+---------+----------------+
| game_id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| creation_time | datetime | NO | | NULL | |
| last_action_time | datetime | NO | | NULL | |
| player_1_id | int(10) unsigned | NO | MUL | NULL | |
| player_2_id | int(10) unsigned | NO | MUL | NULL | |
| dollar_amount | decimal(11,2) | NO | MUL | NULL | |
| amulet_game | tinyint(3) unsigned | NO | MUL | NULL | |
| amulet_game_wait_time | datetime | NO | MUL | NULL | |
| started | tinyint(3) unsigned | NO | | NULL | |
| round_number | int(10) unsigned | NO | | NULL | |
| game_square | char(125) | NO | | NULL | |
| player_1_got_start | tinyint(4) | NO | | NULL | |
| player_2_got_start | tinyint(4) | NO | | NULL | |
| player_1_moves | char(13) | NO | | NULL | |
| player_2_moves | char(13) | NO | | NULL | |
| player_1_bet_made | tinyint(3) unsigned | NO | | NULL | |
| player_2_bet_made | tinyint(3) unsigned | NO | | NULL | |
| player_1_ended_round | tinyint(3) unsigned | NO | | NULL | |
| player_2_ended_round | tinyint(3) unsigned | NO | | NULL | |
| move_deadline | datetime | NO | | NULL | |
| player_1_coins | tinyint(3) unsigned | NO | | NULL | |
| player_2_coins | tinyint(3) unsigned | NO | | NULL | |
| player_1_pot_coins | tinyint(3) unsigned | NO | | NULL | |
| player_2_pot_coins | tinyint(3) unsigned | NO | | NULL | |
| settled_pot_coins | tinyint(3) unsigned | NO | | NULL | |
| semaphore_key | int(10) unsigned | NO | | NULL | |
+-----------------------+---------------------+------+-----+---------+----------------+
26 rows in set (0.00 sec)
CREATE语句:
"CREATE TABLE $tableName(" .
"game_id BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT," .
"creation_time DATETIME NOT NULL,".
"last_action_time DATETIME NOT NULL,".
"player_1_id INT UNSIGNED NOT NULL," .
"INDEX( player_1_id )," .
"player_2_id INT UNSIGNED NOT NULL," .
"INDEX( player_2_id )," .
"dollar_amount DECIMAL(11, 2) NOT NULL,".
"INDEX( dollar_amount )," .
"amulet_game TINYINT UNSIGNED NOT NULL,".
"INDEX( amulet_game ),".
// wait for a random amount of time before
// settling on an opponent for an amulet game
"amulet_game_wait_time DATETIME NOT NULL,".
"INDEX( amulet_game_wait_time ),".
"started TINYINT UNSIGNED NOT NULL,".
"round_number INT UNSIGNED NOT NULL," .
// 36-cell square, numbers from 1 to 36, separated by #
// character
"game_square CHAR(125) NOT NULL,".
// flag set when each player requests the very first game
// state. This indicates that both are aware that the game
// has started, so leave penalties can be assessed
"player_1_got_start TINYINT NOT NULL,".
"player_2_got_start TINYINT NOT NULL,".
"player_1_moves CHAR(13) NOT NULL,".
"player_2_moves CHAR(13) NOT NULL,".
"player_1_bet_made TINYINT UNSIGNED NOT NULL,".
"player_2_bet_made TINYINT UNSIGNED NOT NULL,".
"player_1_ended_round TINYINT UNSIGNED NOT NULL,".
"player_2_ended_round TINYINT UNSIGNED NOT NULL,".
"move_deadline DATETIME NOT NULL,".
"player_1_coins TINYINT UNSIGNED NOT NULL, ".
"player_2_coins TINYINT UNSIGNED NOT NULL, ".
"player_1_pot_coins TINYINT UNSIGNED NOT NULL, ".
"player_2_pot_coins TINYINT UNSIGNED NOT NULL, ".
// coins in both pots that are common knowledge to both players
// (coins that have been matched by opponent to move on
// to next turn)
"settled_pot_coins TINYINT UNSIGNED NOT NULL, ".
"semaphore_key INT UNSIGNED NOT NULL ) ENGINE = INNODB;"
ext/mysql
版本的源代码时,出现错误“无法保存结果集”
:
if(使用存储==MYSQL\u使用结果){
mysql\u result=mysql\u use\u result(mysql->conn);
}否则{
mysql\u result=mysql\u store\u result(mysql->conn);
}
如果(!mysql_result){
如果(PHP\u MYSQL\u VALID\u RESULT(MYSQL->conn)){/*查询应该返回行*/
php_错误_docref(空TSRMLS_CC,E_警告,“无法保存结果集”);
查看PHP\u MYSQL\u VALID\u结果的
#定义PHP_MYSQL_有效_结果(MYSQL)\
(mysql_字段_计数(mysql)>0)
很明显,要出现此错误,mysql\u store\u result()
必须返回NULL
但mysql\u field\u count()
必须返回正数。后一个函数的mysql C API声明:
此函数的正常使用是在返回NULL
(因此您没有结果集指针)时。在这种情况下,您可以调用以确定是否应生成非空结果。这使客户端程序能够在不知道查询是否是(或类似)语句的情况下采取适当的操作
好吧,这似乎正好描述了您的案例中出现的情况。以下链接:
成功调用后,可以返回NULL
。发生这种情况时,表示出现以下情况之一:
- 出现
malloc()
故障(例如,如果结果集太大)
- 无法读取数据(连接上发生错误)
- 查询没有返回任何数据(例如,它是一个、或)
由于该情况是在执行SELECT
查询时出现的,并且没有任何连接错误的迹象(我认为如果是这种情况,客户端会删除该错误),因此该错误的最可能原因似乎是malloc()
failure。对malloc()
可能失败的情况给出了很好的解释
我通过在服务器达到100%使用率时释放服务器磁盘空间来解决这个问题
此问题已记录在/var/log/mysql/error.log中,因此我总是在做任何事情之前先检查错误日志。这是一个PHP错误,而不是mysql错误。要确定问题,您需要提供有关执行此命令的PHP上下文的进一步信息。不,不是phpinfo-!生成和执行此命令的PHP代码使用更新。首先-停止使用
mysql
扩展,因为它已被弃用。尝试重写您的代码以使用mysqli
或pdo
。@PaulTomkiel:对于一个显然是一个大型的现有代码库的现有项目,这现在可能不是一个非常有用的建议…@FélixGagnon Grenier:MySQL文档清楚地说明了可能发生此故障的情况,这不是由于锁冲突造成的(这通常只会导致一个查询排队,直到这些锁被释放,可能会超时,除非出现死锁,在这种情况下会引发错误).Op在内存限制为96M的最大10行表上进行了测试。阅读ops文章第3段时,RTFS lulz。不管eggyal如何,都有很多好信息。@Brian:仅仅因为所讨论的查询很小并不意味着MySQL没有耗尽内存。例如,如果MySQL已经消耗了除1KB以外的所有内存分配,那么查询仍可能导致malloc()
失败。不确定你的第二句话是什么意思?奇怪的是,错误和警告是通过我的自定义日志机制记录的,它实际上从同一个线程和连接将日志条目插入到同一个数据库中。再加上每天有20K个查询正常运行
function cm_getNewSquare() {
global $tableNamePrefix;
// have it wrap around at the 32-bit unsigned max
// because getMagicSquare6 takes a 32-bit unsigned seed.
// we store it as a BIGINT to keep it from getting stuck on the same
// square after four billion games
$query = "SELECT next_magic_square_seed % 4294967296 ".
"FROM $tableNamePrefix".
"server_globals FOR UPDATE;";
$result = cm_queryDatabase( $query );
mysql> describe minuetServer_games;
+-----------------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------+---------------------+------+-----+---------+----------------+
| game_id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| creation_time | datetime | NO | | NULL | |
| last_action_time | datetime | NO | | NULL | |
| player_1_id | int(10) unsigned | NO | MUL | NULL | |
| player_2_id | int(10) unsigned | NO | MUL | NULL | |
| dollar_amount | decimal(11,2) | NO | MUL | NULL | |
| amulet_game | tinyint(3) unsigned | NO | MUL | NULL | |
| amulet_game_wait_time | datetime | NO | MUL | NULL | |
| started | tinyint(3) unsigned | NO | | NULL | |
| round_number | int(10) unsigned | NO | | NULL | |
| game_square | char(125) | NO | | NULL | |
| player_1_got_start | tinyint(4) | NO | | NULL | |
| player_2_got_start | tinyint(4) | NO | | NULL | |
| player_1_moves | char(13) | NO | | NULL | |
| player_2_moves | char(13) | NO | | NULL | |
| player_1_bet_made | tinyint(3) unsigned | NO | | NULL | |
| player_2_bet_made | tinyint(3) unsigned | NO | | NULL | |
| player_1_ended_round | tinyint(3) unsigned | NO | | NULL | |
| player_2_ended_round | tinyint(3) unsigned | NO | | NULL | |
| move_deadline | datetime | NO | | NULL | |
| player_1_coins | tinyint(3) unsigned | NO | | NULL | |
| player_2_coins | tinyint(3) unsigned | NO | | NULL | |
| player_1_pot_coins | tinyint(3) unsigned | NO | | NULL | |
| player_2_pot_coins | tinyint(3) unsigned | NO | | NULL | |
| settled_pot_coins | tinyint(3) unsigned | NO | | NULL | |
| semaphore_key | int(10) unsigned | NO | | NULL | |
+-----------------------+---------------------+------+-----+---------+----------------+
26 rows in set (0.00 sec)
"CREATE TABLE $tableName(" .
"game_id BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT," .
"creation_time DATETIME NOT NULL,".
"last_action_time DATETIME NOT NULL,".
"player_1_id INT UNSIGNED NOT NULL," .
"INDEX( player_1_id )," .
"player_2_id INT UNSIGNED NOT NULL," .
"INDEX( player_2_id )," .
"dollar_amount DECIMAL(11, 2) NOT NULL,".
"INDEX( dollar_amount )," .
"amulet_game TINYINT UNSIGNED NOT NULL,".
"INDEX( amulet_game ),".
// wait for a random amount of time before
// settling on an opponent for an amulet game
"amulet_game_wait_time DATETIME NOT NULL,".
"INDEX( amulet_game_wait_time ),".
"started TINYINT UNSIGNED NOT NULL,".
"round_number INT UNSIGNED NOT NULL," .
// 36-cell square, numbers from 1 to 36, separated by #
// character
"game_square CHAR(125) NOT NULL,".
// flag set when each player requests the very first game
// state. This indicates that both are aware that the game
// has started, so leave penalties can be assessed
"player_1_got_start TINYINT NOT NULL,".
"player_2_got_start TINYINT NOT NULL,".
"player_1_moves CHAR(13) NOT NULL,".
"player_2_moves CHAR(13) NOT NULL,".
"player_1_bet_made TINYINT UNSIGNED NOT NULL,".
"player_2_bet_made TINYINT UNSIGNED NOT NULL,".
"player_1_ended_round TINYINT UNSIGNED NOT NULL,".
"player_2_ended_round TINYINT UNSIGNED NOT NULL,".
"move_deadline DATETIME NOT NULL,".
"player_1_coins TINYINT UNSIGNED NOT NULL, ".
"player_2_coins TINYINT UNSIGNED NOT NULL, ".
"player_1_pot_coins TINYINT UNSIGNED NOT NULL, ".
"player_2_pot_coins TINYINT UNSIGNED NOT NULL, ".
// coins in both pots that are common knowledge to both players
// (coins that have been matched by opponent to move on
// to next turn)
"settled_pot_coins TINYINT UNSIGNED NOT NULL, ".
"semaphore_key INT UNSIGNED NOT NULL ) ENGINE = INNODB;"