2015-12-21 4 views
0

У меня есть функция, которая берет имя категории и возвращает все группы фильтров, связанные с этой категорией, а также фильтры, связанные с каждой группой. Но слишком много циклов и запросов продолжается, есть ли способ улучшить код ниже?SQL-запрос со слишком большим количеством циклов

public function getCategoryFilters($category_id) { 

    // get category filter groups 
    $query = $this->app['db']->query("SELECT filter_group_id 
    FROM " . DB_PREFIX . "category_filter 
    WHERE category_id = '" . (int)$category_id . "' 
    "); 

    if($query->rows) : 
     foreach ($query->rows as $group) : 

      $filter_group_query = $this->app['db']->query(" 
      SELECT DISTINCT fg.filter_group_id, fgd.name, fg.sort_order 
      FROM " . DB_PREFIX . "filter_group fg 
      LEFT JOIN " . DB_PREFIX . "filter_group_description fgd ON (fg.filter_group_id = fgd.filter_group_id) 
      WHERE fg.filter_group_id = '" . $group['filter_group_id'] . "' 
      AND fgd.language_id = '1' 
      GROUP BY fg.filter_group_id 
      ORDER BY fg.sort_order, LCASE(fgd.name)"); 

      foreach ($filter_group_query->rows as $filter_group) : 
       $filter_data = array(); 

       $filter_query = $this->app['db']->query(" 
        SELECT DISTINCT f.filter_id, fd.name FROM " . DB_PREFIX . "filter f 
        LEFT JOIN " . DB_PREFIX . "filter_description fd ON (f.filter_id = fd.filter_id) 
        WHERE f.filter_group_id = '" . (int)$filter_group['filter_group_id'] . "' 
        AND fd.language_id = '1' 
        ORDER BY f.sort_order, LCASE(fd.name)"); 

       foreach ($filter_query->rows as $filter) : 
        $filter_data[] = array(
          'filter_id' => $filter['filter_id'], 
          'name'  => $filter['name'] 
        ); 
       endforeach; 

       if ($filter_data) : 
        $filter_group_data[] = array(
          'filter_group_id' => $filter_group['filter_group_id'], 
          'name'   => $filter_group['name'], 
          'filter'   => $filter_data 
        ); 
       endif; 

      endforeach; 

     endforeach; 

     return $filter_group_data; 

    endif; 
} 

ответ

2

Ответ зависит от того, что вы имеете в виду под «улучшить». Если вы хотите улучшить читаемость кода и убедитесь, что кто-то может понять его позже, тогда вы должны создать подфункции, как предположил Матей Михай в своем ответе.

Я хотел бы сделать это так (псевдокод):

public function getCategoryFilters($category_id) { 
    //Declare subfunctions 
    //Get the data concerning group filters 
    private function getFilterGroupData($category_id) { 
     ... 
     mysqli query here 
     ... 
     $result = array(); 
     insert query results into $result using a loop 
     return $result; 
    } 

    //Get specific filter data 
    private function getFilterData($filter_group_id) { 
     ... 
     mysqli query here 
     ... 
     $result = array(); 
     insert query results into $result using a loop: 
     for ($i = 0, $i < $mysqli_query->num_rows; $i += 1) { 
      ... 
     //Add $filter_group_id right here as you seem to need it in the results: 
      $result[$i]['filter_group_id'] = $filter_group_id; 
     } 
     return $result; 
    } 

    //Get the data you need, populate an array with all the results 
    $filter_groups_data = getFilterGroupData($category_id); 
    $count = count($filter_groups_data); 
    $all_filters_data = array(); 
    for ($i = 0; $i < $count; $i += 1) { 
     $filter_data = getFilterData($filter_groups_data[$i]; 
     //Insert into final results 
     array_push($all_filters_data, $filter_data); 
    } 
    return $all_filters_data; 
} 

Однако, если вы хотите, чтобы уменьшить количество запросов вместо этого, вы можете написать более сложный запрос, делая объединение filter_group, filter_group_description, фильтровать и фильтровать_описание таблиц прямо с места в карьер, а затем прокручивать результаты только один раз.

Вы должны учитывать это только в том случае, если у вас возникают проблемы со скоростью выполнения скрипта, поскольку запрос будет намного менее читаемым. В принципе, просто пойти:

SELECT ... FROM 
filter_group 
INNER JOIN filter_group_description ON filter_group_id 
INNER JOIN filter ON filter_group_id 
INNER JOIN filter_description ON filter_id 
WHERE ... 
ORDER BY ...; 

Если вы идете по этому пути, хотя, не забудьте оставить комментарий, описывающий только как запрос работает, как SQL внутри PHP скрипт с несколькими JOIN и, как известно, трудно отлаживать и изменения.

+0

Я реализую оба метода и вижу разницу между ними по времени выполнения. в случае, если второе предложение будет работать быстрее, я буду комментировать решения функций и держать его в качестве ссылки на то, что происходит на самом деле. Большое спасибо. – user1709251

0

Вы можете сделать метод для каждого цикла. Поступая таким образом, вы увеличите читаемость и упростить код:

public function getCategoryFilters($category_id) {} 

public function getFilterData($filterGroupIds) {} 

// ..... 
+0

Правда. Но я ищу что-то, чтобы улучшить производительность этого запроса. – user1709251

1

вы можете использовать пункт in, чтобы уменьшить время запроса; так:

foreach ($query->rows as $group) : 
    $filter_group_ids[] = $group['filter_group_id']; 
endforeach; 

     $filter_group_query = $this->app['db']->query(" 
     SELECT DISTINCT fg.filter_group_id, fgd.name, fg.sort_order 
     FROM " . DB_PREFIX . "filter_group fg 
     LEFT JOIN " . DB_PREFIX . "filter_group_description fgd ON (fg.filter_group_id = fgd.filter_group_id) 
     WHERE fg.filter_group_id IN ('" . implode("','",$filter_group_ids) . "') 
     AND fgd.language_id = '1' 
     GROUP BY fg.filter_group_id 
     ORDER BY fg.sort_order, LCASE(fgd.name)"); 
Смежные вопросы