在简单的mysql select查询中允许内存大小超过256mb


Allowed memory size exceeding 256mb on simple mysql select query

编辑:对于任何发现这在以后的日期CI将使用大量的内存在这些类型的情况下,因为它会为每一行创建一个对象(使用result_array()似乎没有更好),所以最好的选择只是使用PHP的内置mysql函数。如果你正在使用mysql,你可以像这样访问连接链接:

$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 ;

有24万行。

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

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

但是我得到一个允许的内存大小错误,像这样:

允许内存大小268435456字节耗尽(试图分配92字节)xxx/codeigniter_2.0.3/数据库/司机/mysqli mysqli_result.php第167行

我意识到简单的答案是我内存不足,但这似乎荒谬的只是做一个选择查询,特别是高允许的内存大小为256mb。

谁能提出一个原因吗?这可能与编码器和它构建结果对象的方式有关吗?

好,假设我们处理的是最小值(这里只使用声明的大小),每行数据是624字节。这有点轻描淡写,因为许多可变宽度字段需要额外的空间来说明它们实际有多大。考虑到所有这些都将被转换为内部PHP样式,我们可能会在这里添加更多内容(结果以数组形式返回,根据设置可能是散列)。但实际上,在这一切都说完了之后,我们可能要处理每条记录大约2kb的数据。

而且,我们正在处理其中的120,000个。120000 * 2048 = 245760000字节= 234.4 MB的数据。PHP有它的开销,编码器也是如此。这些加在一起就足够让你超过内存限制了。

如果您想更好地估计正在使用多少内存,请继续并调高内存使用限制,然后在执行select查询之后,检查memory_get_usage()。

要减少内存使用,您可以通过添加额外的where子句来减少所选择的行数,只选择必要的列而不是所有列,或者使用LIMIT语句。如果您选择LIMIT路线,则可以处理所有记录和所有列,但是以块的形式处理。每个select语句可以返回有限数量的行,比如100行,但是您可以让每个后续调用从另一个调用结束的地方继续。这样,在给定的时间内,内存中的数据永远不会超过100行。

对于大数据,我们需要使用mysql resource而不是CI函数

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