【问题标题】:Yii large SQL queries consumes a large amount of memoryYii大型SQL查询消耗大量内存
【发布时间】:2014-12-04 13:12:27
【问题描述】:

我在 centos 6 上使用 Yii 1.1.14 和 php 5.3,我使用 CDbCommand 从一个非常大的表中获取数据,结果集是超过 10 列的约 90,000 条记录我将它导出到一个 csv 文件和文件大小约为15MB, 脚本总是在没有任何错误消息的情况下崩溃,只有经过一些研究后,我才发现我需要提高 php.ini 中的 memory_limit 才能成功执行脚本。 唯一的问题是,为了成功执行,我必须将内存限制提高到 512MB(!),这是很多!如果 10 个用户将执行相同的脚本,我的服务器将不会很好地响应......

我想知道是否有人知道使用 Yii 减少 sql 查询的内存消耗的方法? 我知道我可以使用限制和偏移量将查询拆分为多个查询,但是 15MB 的查询会消耗 512MB 似乎不合逻辑。

代码如下:

set_time_limit(0);
$connection = new CDbConnection($dsn,$username,$password);
$command = $connection->createCommand('SELECT * FROM TEST_DATA');
$result = $command->queryAll(); //this is where the script crashes
print_r($result);

任何想法将不胜感激!

谢谢,

【问题讨论】:

  • 您确定问题不在数据库上吗?如果它是一个非常大的查询,你可能会超时而不是耗尽它的内存。我假设你在 MySQL 上。也许尝试一些索引来加速它,否则你会遇到限制和偏移或迁移到 NoSQL 解决方案
  • 所以您认为如果将某些内容写入文件时占用 15MB,那么在将其转换为保存信息的语言的数据结构时,它必须分配相同数量的内存?但是要用您已经(正确)猜到的内容来回答您的问题 - 使用 LIMIT 和 OFFSET。不要一次加载所有内容。在移动到接下来的 5k 行之前,计算您有多少行并对 5k 行执行操作 - 直到完成所有 90k。
  • 您好,感谢您的回复! @mike miller,不应该有时间问题,因为脚本很快就失败了约 5 秒,我已将时间限制设置为 0..

标签: php apache yii


【解决方案1】:

而不是使用 readAll 将返回单个数组中的所有行(真正的内存问题在这里),您应该简单地使用 foreach 循环(看看CDbDataReader),例如:

$command = $connection->createCommand('SELECT * FROM TEST_DATA');
$rows = $command->query();
foreach ($rows as $row)
{

}

编辑:使用限制

$count = Yii::app()->db->createCommand('SELECT COUNT(*) FROM TEST_DATA')->queryScalar();
$maxRows = 1000:
$maxPages = ceil($count / $maxRows);

for ($i=0;$i<$maxPages;$i++)
{
    $offset = $i * $maxRows;
    $rows = $connection->createCommand("SELECT * FROM TEST_DATA LIMIT $offset,$maxRows")->query();
    foreach ($rows as $row)
    {
      // Here your code
    }
}

【讨论】:

  • 您好,这个方法非常好,使用您的示例我能够创建一个 16MB 的文件,其中大约有 ~110,000 条记录,所以这是一个 ~20% 的改进!但脚本仍然在 $rows = $command->query(); 处失败当试图获得更多记录时......有什么想法吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-16
  • 2014-01-04
  • 2012-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-02
相关资源
最近更新 更多