如何限制从雄辩查询中检索到的信息并阻止它崩溃?

时间:2015-04-19 00:29:17

标签: php mysql laravel eloquent laravel-5

以下代码遍历整个公司数据库并缓存较低级别的嵌套关系,以便以后可以访问它们。当数据超过约20,000公司和约500,000个嵌套关系时,这会占用大量内存并死亡。如何修改它(将其更改为原始SQL或Laravel查询构建器语句),以便它仅加载我需要的信息并提高其性能? (足以计算条目状态)。

嵌套关系如下

  1. 公司> (有很多)地点> (有很多)设备> (具有 许多)项目> (有一个)订单
  2. 公司> (有很多)协议> (有很多)设备
  3. 公司> (有很多)潜在客户
  4. 公司> (有很多)发票
  5. 脚本应该为每个公司输出以下内容的计数

    1. maintainCount - 活动设备的数量(即具有状态 '有效')对有效协议(即状态为 '未签名','有效'或'到期时取消')
    2. equipmentCount - 活动设备的数量(即带有 状态为“活跃”)
    3. leadCount - 活跃线索的数量(即状态为 '打开')
    4. invoiceCount - 有效发票的数量(即状态为 '待定'或'完成')
    5. projectCount - 活动项目的数量(即状态为 '待定'或'完成')
    6. orderCount - 活动订单的数量(即状态为 '待定'或'完成')
    7. 当前脚本如下;

      Company::chunk(50, function($companies) {
        foreach ($companies as $company) {
          $maintainedCount = 0;
          $equipmentCount = 0;
          $leadCount = 0;
          $invoiceCount = 0;
          $projectCount = 0;
          $orderCount = 0;
          foreach ($company->agreements as $agreement) {
            if (in_array($agreement->status, ['Unsigned', 'Active', 'Cancel on Expiry'])) {
              $maintainedCount += $agreement->equipment->where('status', 'Active')->count();
            }
          }
          $equipmentCount = $company->equipment->where('status', 'Active')->count();
          $unmaintainedCount = ($equipmentCount - $maintainedCount);
          $leadCount= $company->leads->where('status', 'Open')->count();
          foreach ($company->invoices as $invoice) {
            if (in_array($invoice->status, ['Pending', 'Complete'])) {
              $invoiceCount += 1;
            }
          }    
          foreach ($company->equipment as $equipment) {
            foreach ($equipment->projects as $project) {
              if (in_array($project->status, ['Pending', 'Complete'])) {
                $projectCount += 1;
              }
              if($project->order <> null) {
                if (in_array($project->order->status, ['Pending', 'Complete'])) {
                  $orderCount += 1;
                }
              }
            }
          }
          DB::table('companies')->where('id', $company->id)->update(['unmaintained_count' => $unmaintainedCount, 'lead_count' => $leadCount, 'project_count' => $projectCount, 'order_count' => $orderCount, 'invoice_count' => $invoiceCount]);
        }
      });
      $this->info('Company count cache updated!');
      

1 个答案:

答案 0 :(得分:0)

好的,我通过将其转换为直接SQL查询(4gb +到100mb)解决了内存使用问题

DB::connection()->disableQueryLog();
$start = microtime(true);
Company::chunk(50, function($companies) {
    foreach ($companies as $company) {
        $maintainedCount = 0;
        $equipmentCount = 0; 
        $leadCount = 0;
        $invoiceCount = 0;
        $projectCount = 0; 
        $orderCount = 0;
        $maintainedCount = reset(DB::select(DB::raw('SELECT COUNT(*) FROM (
                                    SELECT equipment.id FROM equipment
                                    INNER JOIN agreements ON agreements.id = equipment.agreement_id 
                                    WHERE agreements.company_id = :companyId
                                    AND equipment.status = "Active"
                                    AND (agreements.status = "Active" OR agreements.status = "Unsigned" OR agreements.status = "Cancel on Expiry")) AS QUERY;'), 
                                    ['companyId' => $company->id])[0]);
        $equipmentCount = $company->equipment->where('status', 'Active')->count();
        $unmaintainedCount = ($equipmentCount - $maintainedCount);
        $leadCount= $company->leads->where('status', 'Open')->count();
        $invoiceCount = reset(DB::select(DB::raw('SELECT COUNT(*) FROM (
                                            SELECT invoices.id
                                            FROM invoices
                                            WHERE invoices.company_id = :companyId
                                            AND (invoices.status = "Pending" OR invoices.status = "Complete")) AS QUERY;'), 
                                            ['companyId' => $company->id])[0]);         
        $projectCount = reset(DB::select(DB::raw('SELECT COUNT(*) FROM (
                                                  SELECT projects.id FROM projects
                                                  INNER JOIN equipment ON equipment.id = projects.equipment_id
                                                  INNER JOIN locations ON locations.id = equipment.location_id
                                                  WHERE locations.company_id = :companyId
                                                  AND (projects.status = "Pending" OR projects.status = "Complete")) AS QUERY;'), 
                                                  ['companyId' => $company->id])[0]);               
        $orderCount = reset(DB::select(DB::raw('SELECT COUNT(*) FROM (
                                                SELECT orders.id FROM orders
                                                INNER JOIN projects ON projects.id = orders.project_id
                                                INNER JOIN equipment ON equipment.id = projects.equipment_id
                                                INNER JOIN locations ON locations.id = equipment.location_id
                                                WHERE locations.company_id = :companyId
                                                AND (orders.status = "Pending" OR orders.status = "Complete")) AS QUERY;'), 
                                                ['companyId' => $company->id])[0]);
        DB::table('companies')->where('id', $company->id)->update(['unmaintained_count' => $unmaintainedCount, 'lead_count' => $leadCount, 'project_count' => $projectCount, 'order_count' => $orderCount, 'invoice_count' => $invoiceCount]);
    }
});
$duration = number_format((microtime(true) - $start), 2);
$this->info('Company count cache updated! (it took '.$duration.' seconds)');