简单的mysql选择查询允许的内存大小超过256mb

时间:2011-10-19 17:42:05

标签: php mysql codeigniter

编辑:对于任何在以后发现这种情况的人来说,CI会在这种情况下使用大量内存,因为它会为每一行创建一个对象(使用result_array()看起来好不多),所以最好的选择只是使用PHP内置的mysql函数。如果你正在使用MYSQLI,你可以像这样访问连接链接:

$this->db->conn_id

我正在尝试通过命令行运行脚本(测试将是一个cronjob),脚本所做的是无关紧要的,因为它在第一次选择时失败并且没有得到任何进一步。

我正在使用Codeigniter 2.0.3。

我的表格如下:

CREATE TABLE IF NOT EXISTS `graphic_files` (
  `graphic_file_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `graphic_file_style_id` tinyint(2) unsigned NOT NULL,
  `graphic_file_fm_id` bigint(20) unsigned DEFAULT NULL,
  `graphic_file_config_line` varchar(255) NOT NULL,
  `graphic_file_config_line_hash` varchar(32) NOT NULL,
  `graphic_file_location` varchar(255) DEFAULT NULL,
  `graphic_file_pack_id` int(10) unsigned NOT NULL,
  `graphic_file_enabled` tinyint(1) NOT NULL,
  `graphic_file_alternative` tinyint(1) NOT NULL,
  `graphic_file_version` decimal(4,2) NOT NULL,
  `graphic_file_time_added` int(11) unsigned NOT NULL,
  `graphic_file_time_modified` int(11) unsigned NOT NULL,
  `graphic_file_size` int(11) unsigned NOT NULL,
  PRIMARY KEY (`graphic_file_id`),
  KEY `graphic_file_style_id` (`graphic_file_style_id`),
  KEY `graphic_file_fm_id` (`graphic_file_fm_id`),
  KEY `graphic_file_config_line_hash` (`graphic_file_config_line_hash`),
  KEY `graphic_file_pack_id` (`graphic_file_pack_id`),
  KEY `graphic_file_enabled` (`graphic_file_enabled`),
  KEY `graphic_file_version` (`graphic_file_version`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=240752 ;

有240,000行。

我试图用这个查询选择大约120,000个:

SELECT * FROM graphic_files WHERE graphic_file_enabled = 0 AND graphic_file_style_id = 5

但我得到一个允许的内存大小错误:

  

允许的内存大小为268435456字节耗尽(尝试分配92   字节)   xxx / codeigniter_2.0.3 / database / drivers / mysqli / mysqli_result.php on   第167行

我意识到简单的答案是我内存不足,但这对于简单地执行选择查询来说似乎很荒谬,特别是对于256mb的高允许内存大小。

有人可以提出理由吗?可能与codeigniter及其构建结果对象的方式有关吗?

2 个答案:

答案 0 :(得分:9)

好的,假设我们正在处理最低限度(仅使用声明的大小),每行数据为624字节。这有点轻描淡写,因为许多可变宽度字段需要额外的空间来记录它们实际有多大。鉴于所有这些都将转换为内部PHP样式,我们可能会在那里进行更多处理(结果作为数组返回,可能是根据设置的哈希)。但实际上,在完成所有操作后,我们可能会处理总计近2kb的记录。

另外,我们正在处理其中的120,000个。 120000 * 2048 = 245760000字节= 234.4 MB的数据。 PHP有它的开销,codeigniter也是如此。总之,这足以让你超越内存限制。

如果您想更好地估计正在使用的内存量,请继续并提高内存使用量限制,然后在执行选择查询后,请检查memory_get_usage()

您可以采取哪些措施来减少内存使用量,或者通过添加额外的where子句来减少所选行的数量,只选择必要的列而不是所有列,或者使用LIMIT语句。如果你进入LIMIT路线,你可以处理所有记录和所有列,但是以块为单位。每个select语句都可以返回有限数量的行,比如100,但是你可以让每个后续的调用恢复到另一个停止的地方。这样,在给定时间内,内存中永远不会有超过100行数据。

答案 1 :(得分:5)

对于大数据,您需要使用mysql resource而不是CI功能

$result = $this->db->query($sql);
$resource = $result->result_id;
while($row = @mysql_fetch_assoc($resource)) {
    // do the magic
}