Я новичок в stackoverflow, примите мои извинения за длинный вопрос. У меня есть большая база данных розничной торговли. Мы хотели подготовить отчет, чтобы получить баланс открытия и закрытия продуктов, продукция имеет номер партии, и каждая партия имеет уникальный серийный номер, который присваивается нескольким местоположениям. Задача состоит в том, чтобы получить начальные балансы каждой партии выбранного продукта для каждого местоположения склада. Если местоположение не указано в фильтре отчетов, отчет должен давать результат для выбранного продукта и всех его партий.MySQL/PHP, ForEach Loops slow
Я получаю все места, используя PHP/PDO, и прохожу через него, так как в первом цикле я получаю все партии против выбранного продукта, а в цикле партий я сначала получаю начальный баланс (который рассчитывается как, сумма количества до фильтра даты), затем вычисляю количество, полученное от партии этого продукта в этом месте (сумма количества, полученная в фильтре от и до даты), затем количество проданного или количество, перемещенное на другие склады (сумма количества перемещен на другой склад в выбранном из фильтра и до даты).
Теперь я могу рассчитать баланс закрытия, поскольку у меня есть все значения. Это работает нормально, но когда запрос выполняется для 20 складов, а для одного продукта почти 20+ партий, отчет занимает много времени, а использование процессоров MySQL достигает 200%.
Я попытался оптимизировать запросы, мои таблицы были правильно проиндексированы. В таблицах много данных. миллионы записей. Мне нужно посоветовать, как улучшить мой код или методы, что я делаю неправильно и как сделать отчет быстрее.
Я использую заголовок для моего приложения, а следующий код.
foreach($locations as $loc){
//if batch is selected put it in array
if($query_array['batch_no'] != ''){
$batches[] = $query_array['batch_no'];
}else{
// or get all batches from the inventory table for the location
$this->db->select('distinct(batch_no)');
$this->db->from('product_details');
$this->db->where('product_id',$query_array ['product']);
$this->db->where('warehouse_id',$loc);
$query = $this->db->get();
foreach($query->result() as $row){
$batches[] = $row->batch_no;
}
$query->free_result();
}
foreach($batches as $batch){
//GIN IN Opening Balance
$this->db->select('IFNULL(SUM(gi.qty),0) as gin_in',FALSE);
$this->db->from('gin as g');
$this->db->join('gin_items as gi','gi.gin_id=g.id');
$this->db->where('gi.product_id',$query_array ['product']);
$this->db->where('DATE(g.creation_date) < ',$query_array ['date_from']);
$this->db->where('g.to_location_id', $loc);
$this->db->where_in('gi.batch_no',$batch);
$this->db->where_in('gi.status',2);
$this->db->where('g.status',3);
$query = $this->db->get();
if($query->num_rows()==1)
{
$var1=$query->row()->gin_in;
$query->free_result();
}
// SUM (Return Invoices for a specific product, for this particular store,
// before this date range) -> $var2
$this->db->select('IFNULL(SUM(ii.qty),0) as sale_return_in',FALSE);
$this->db->from('return_sales_invoice rs');
$this->db->join('return_invoice_items as ii','ii.invoice_id=rs.id');
$this->db->where('ii.medicine_id',$query_array ['product']);
$this->db->where_in('ii.batch_no',$batch);
$this->db->where_in('rs.location_id',$loc);
$this->db->where('rs.dated < ',$query_array ['date_from']);
$query = $this->db->get();
if($query->num_rows()==1){
$var2=$query->row()->sale_return_in;
$query->free_result();
}
//SUM (Sales Invoices of a specific product, from this particular store,
// before this date range) -> $var3
$this->db->select('IFNULL(SUM(ii.qty),0) as sale_out',FALSE);
$this->db->from('sales_invoice si');
$this->db->join('invoice_items as ii','ii.invoice_id=si.id');
$this->db->where('ii.medicine_id',$query_array ['product']);
$this->db->where_in('ii.batch_no',$batch);
$this->db->where_in('si.location_id',$loc);
$this->db->where('si.dated < ',$query_array ['date_from']);
$query = $this->db->get();
if($query->num_rows()==1){
$var3=$query->row()->sale_out;
$query->free_result();
}
// SUM (GIN of a specific product, from this particular store,
// before this date range) -> $var4
// if from location then minis stock
$this->db->select('IFNULL(SUM(gi.qty),0) as gin_out',FALSE);
$this->db->from('gin as g');
$this->db->join('gin_items as gi','gi.gin_id=g.id');
$this->db->where('DATE(g.creation_date) < ',$query_array ['date_from']);
$this->db->where('gi.product_id',$query_array ['product']);
$this->db->where_in('gi.batch_no',$batch);
$this->db->where_in('g.from_location_id',$loc);
$this->db->where('gi.status',2);
$this->db->where('g.status',3);
$query = $this->db->get();
if($query->num_rows()==1){
$var4=$query->row()->gin_out;
$query->free_result();
}
$op_bal = ($var1 + $var2) - ($var3 + $var4);
//---------------------------------------------------------------------------------
$where_from = "DATE(g.creation_date) >='" . $query_array ['date_from'] . "'";
$where_to = "DATE(g.creation_date) <='" . $query_array ['date_to'] . "'";
$rs_where_from = "DATE(rs.creation_date) >='" . $query_array ['date_from'] . "'";
$rs_where_to = "DATE(rs.creation_date) <='" . $query_array ['date_to'] . "'";
$si_where_from = "DATE(si.creation_date) >='" . $query_array ['date_from'] . "'";
$si_where_to = "DATE(si.creation_date) <='" . $query_array ['date_to'] . "'";
//GIN IN Opening Balance
$this->db->select('IFNULL(SUM(gi.qty),0) as gin_in',FALSE);
$this->db->from('gin as g');
$this->db->join('gin_items as gi','gi.gin_id=g.id');
$this->db->where($where_from);
$this->db->where($where_to);
$this->db->where('gi.product_id',$query_array ['product']);
$this->db->where_in('gi.batch_no',$batch);
$this->db->where_in('g.to_location_id', $loc);
$this->db->where('g.status',3);
$this->db->where('gi.status',2);
$query = $this->db->get();
if($query->num_rows()==1){
$g_stock_in=$query->row()->gin_in;
$query->free_result();
}
// SUM (Return Invoices for a specific product, for this particular store,
// before this date range) -> $var2
$this->db->select('IFNULL(SUM(ii.qty),0) as sale_return_in',FALSE);
$this->db->from('return_sales_invoice rs');
$this->db->join('return_invoice_items as ii','ii.invoice_id=rs.id');
$this->db->where('ii.medicine_id',$query_array ['product']);
$this->db->where($rs_where_from);
$this->db->where($rs_where_to);
$this->db->where_in('ii.batch_no',$batch);
$this->db->where_in('rs.location_id',$loc);
$query = $this->db->get();
if($query->num_rows()==1){
$s_stock_in=$query->row()->sale_return_in;
$query->free_result();
}
//SUM (Sales Invoices of a specific product, from this particular store,
// before this date range) -> $var3
$this->db->select('IFNULL(SUM(ii.qty),0) as sale_out',FALSE);
$this->db->from('sales_invoice si');
$this->db->join('invoice_items as ii','ii.invoice_id=si.id');
$this->db->where('ii.medicine_id',$query_array ['product']);
$this->db->where_in('ii.batch_no',$batch);
$this->db->where_in('si.location_id',$loc);
$this->db->where($si_where_from);
$this->db->where($si_where_to);
$query = $this->db->get();
if($query->num_rows()==1){
$s_stock_out=$query->row()->sale_out;
$query->free_result();
}
// SUM (GIN of a specific product, from this particular store,
// before this date range) -> $var4
// if from location then minis stock
$this->db->select('IFNULL(SUM(gi.qty),0) as gin_out',FALSE);
$this->db->from('gin as g');
$this->db->join('gin_items as gi','gi.gin_id=g.id');
$this->db->where($where_from);
$this->db->where($where_to);
$this->db->where('gi.product_id',$query_array ['product']);
$this->db->where_in('gi.batch_no',$batch);
$this->db->where_in('g.from_location_id',$loc);
$this->db->where('g.status',3);
$this->db->where('gi.status',2);
$query = $this->db->get();
if($query->num_rows()==1){
$g_stock_out=$query->row()->gin_out;
$query->free_result();
}
$qty_in=$g_stock_in+$s_stock_in;
$qty_out=$g_stock_out+$s_stock_out;
$productName=$this->getProductName($query_array ['product']);
$locationName=$this->getLocationName($loc);
$data [] = array (
'location' => $locationName,
'product' => $productName,
'batchno' => $batch ,
'op_bal' => $res['op_bal'] ,
'qty_in' => $qty_in,
'qty_out' => $qty_out,
'cl_bal' => ($res['op_bal'] + $qty_in) - $qty_out
);
}
}
return $data;
Добро пожаловать в SO! Быстрая конструктивная критика вашего вопроса: пример кода довольно длинный и может препятствовать волонтерам пытаться его разгадать. Кроме того, вопросы эффективности запросов обычно получают наилучшие результаты, если вы показываете структуру данных и структуры индексов, а также фактические запросы, а не код Ignit Code.Наконец, числовое имя пользователя, а не ваше собственное имя еще больше препятствует людям инвестировать время в вас: многие такие пользователи никогда не возвращаются. Опять же, добро пожаловать! –