Вложенные циклы и SQL-запросы; Жажда Скорости - PullRequest
0 голосов
/ 26 июля 2011

У меня проблемы с решением итеративных SQL-запросов (, с которыми мне нужно справиться ), и я пытаюсь найти альтернативу.

( Также; к сожалению, AJAX не совсем подходит )

Учитывая, что у меня есть следующие таблицы данных о местоположении:

Country
    country_id
    name

State
    state_id
    country_id
    name

City
    city_id
    state_id
    name

Теперь я пытаюсь получить всех данных, однако на самом деле они довольно крошечные ( 147 городов, разделены между 64 штатами, разделены между 2 странами ), однако это занимает навсегда, потому что я циклически повторяюсь:

// this is pseudo-code, but it gets the point across

$countries = getCountries();
foreach($countries as &$country){
    $country['states'] = $states = getStates($country['country_id']);
    foreach($states as &$state){
        $state['cities'] = getCities($state['state_id']);
    }
}

Причина, по которой я иду таким образом, заключается в том, что мой окончательный набор результатов должен быть в форме:

$countries = array(
    array(
        'name' => 'country_name',
        'id' => 'country_id',
        'states' => array(
            array(
                'name' => 'state_name',
                'id' => 'state_id',
                'cities' => array(
                    array(
                        'name' => 'city_name',
                        'id' => 'city_id',
                    ),
                    // ... more cities
                ),
            ),
            // ... more states
        ),
    ),
    // ... more countries
);

Кажется, я не могу быстрее обернуться. Какие существуют альтернативы запрашиванию иерархических данных?


Исправленный вариант:

    $sql = "SELECT
                `dbc_country`.`name` as `country_name`,
                `dbc_state`.`name` as `state_name`,
                `city_id`,
                `dbc_city`.`name` as `city_name`,
                `latitude`,
                `longitude`
            FROM
                `dbc_city`
                    INNER JOIN
                `dbc_state` ON `dbc_city`.`state_id` = `dbc_state`.`state_id`
                    INNER JOIN
                `dbc_country` ON `dbc_state`.`country_id` = `dbc_country`.`country_id`";
    $locations = array();
    foreach($datasource->fetchSet($sql) as $row){
        $locations[$row['country_name']][$row['state_name']][] = array(
            $row['city_id'],
            $row['city_name'],
            $row['latitude'],
            $row['longitude'],
        );
    }

( Я также удалил значения id штатов / стран, так как они бесполезно занимали место )

Ответы [ 4 ]

4 голосов
/ 26 июля 2011

было бы намного быстрее выполнять объединения в sql

, а затем выполнять итерации по одному (большему) набору результатов.

1 голос
/ 26 июля 2011

Я бы использовал один запрос:

SELECT co.name AS CountryName
     , st.name AS StateName
     , ci.name AS CityName
FROM Country AS co
  LEFT JOIN State AS st
    ON st.country_id = co.country_id
  LEFT JOIN City AS ci
    ON ci.state_id = st.state_id
ORDER BY CountryName
       , StateName
       , CityName

или три (если у вас много записей и вас беспокоит отправка "United States of America" сотен тысяч раз по соединению из MySQL с кодом приложения):

--- **GetCountries**
SELECT co.country_id
     , co.name AS CountryName
FROM Country AS co
ORDER BY CountryName

--- **GetStates**
SELECT co.country_id
     , st.state_id
     , st.name AS StateName
FROM Country AS co
  JOIN State AS st
    ON st.country_id = co.country_id
ORDER BY CountryName
       , StateName

--- **GetCities**
SELECT co.country_id
     , st.state_id
     , ci.city_id
     , ci.name AS CityName
FROM Country AS co
  JOIN State AS st
    ON st.country_id = co.country_id
  JOIN City AS ci
    ON ci.state_id = st.state_id
ORDER BY CountryName
       , StateName
       , CityName
0 голосов
/ 26 июля 2011

Что если бы ваши данные выглядели так?

Table: country 
iso_country_code        country_name
--
CA                      Canada
US                      United States of America

Table: state
iso_country_code    state_abbr    state_name
--
US                  NE            Nebraska
CA                  NB            New Brunswick

Table: city
iso_country_code    state_abbr    city_name
--
US                  NE            Lincoln
US                  NE            Arapahoe
CA                  NB            Dalhousie
CA                  NB            Miramichi

Сможете ли вы использовать коды и сокращения вместо полных имен?

Даже если вы не можете, вы можете получить все необходимые строки с помощью одного оператора SELECT, а затем пройтись по строкам, чтобы заполнить ваш массив.(Вы также можете сделать это с помощью идентификационных номеров, но с помощью идентификационных номеров вам всегда нужно выполнять объединения. С помощью кодов и сокращений вы часто можете удовлетворить своих пользователей только кодом или сокращением.)

0 голосов
/ 26 июля 2011

Общий подход к проектированию баз данных подчеркивает выполнение как можно большего объема работы при минимально возможном количестве запросов. Это выглядит правильно. Но, цитируя этот заголовок темы «Эффективность запросов», этот подход не так применим к MySQL. К вашему сведению, MySQL был разработан для очень эффективного управления подключением и отключением и очень быстрого реагирования на небольшие и простые запросы, поэтому, если вы немедленно освобождаете память для своих последовательных запросов, я думаю, это нормально. Кроме того, если ваша запись растет (например, до 100000 записей), возможно, вы дважды подумаете об использовании оператора JOIN.

...