Один SQL-запрос или много в цикле? - PullRequest
3 голосов
/ 03 июня 2009

Мне нужно извлечь несколько строк из таблицы и обработать их двумя способами:

  • агрегировано по ключу
  • строка за строкой, отсортированная по тому же ключу

Таблица выглядит примерно так:

table (
   key,
   string_data,
   numeric_data
)

Итак, я смотрю на два подхода к функции, которую я пишу.

Первый извлекает агрегированные данные одним запросом, а затем снова запрашивает внутри цикла для каждого набора построчных данных (следующий псевдокод похож на PHP):

$rows = query(
        "SELECT key,SUM(numeric_data)
         FROM table
         GROUP BY key"
    );

foreach ($rows as $row) {
    <process aggregate data in $row>

    $key = $row['key'];
    $row_by_row_data = handle_individual_rows($key);
}

function handle_individual_rows($key)
{
    $rows = query(
            "SELECT string_data
             FROM table WHERE key=?",
            $key
        );

    <process $rows one row at a time>

    return $processed_data;
}

Или я мог бы сделать один большой запрос и позволить коду выполнить всю работу:

$rows = query(
    "SELECT key, string_data, numeric_data
     FROM table"
);

foreach ($rows as $row) {
    <process rows individually and calculate aggregates as I go>
}

Производительность не является практической проблемой в этом приложении; Я просто хочу написать разумный и понятный код.

Мне нравится первый вариант, потому что он более модульный, и мне нравится второй вариант, потому что он кажется структурно простым. Один вариант лучше другого или это просто вопрос стиля?

Ответы [ 8 ]

12 голосов
/ 03 июня 2009

Один SQL запрос, конечно.

Это будет

  • Сохраните много поездок в базу данных
  • Позволяет использовать более эффективные GROUP BY методы

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

Вот пример запроса, который возвращает каждую строку и вычисляет SUM:

SELECT  string_data, numeric_data, SUM(numeric_data) OVER (PARTITION BY key)
FROM    table

Обратите внимание, что при этом наиболее вероятно будет использоваться параллельный доступ для вычисления SUM для различных key, что вряд ли реализуемо в PHP.

Тот же запрос в MySQL:

SELECT  key, string_data, numeric_data,
        (
        SELECT  SUM(numeric_data)
        FROM    table ti
        WHERE   ti.key = to.key
        ) AS key_sum
FROM    table to
0 голосов
/ 08 июня 2009

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

0 голосов
/ 04 июня 2009

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

  • если вы хотите, чтобы все читалось и поддерживалось, смешивание обоих в одном запросе не будет правильным, запрос будет отвечать двум различным потребностям, поэтому он не будет очень читабельным

  • даже если perf не является проблемой, агрегирование на сервере БД выполняется быстрее, чем в коде

  • только с одним запросом код, который будет обрабатывать результат, будет смешивать две обработки, обрабатывать строки и вычислительные агрегации одновременно, поэтому со временем этот код будет становиться запутанным и ошибочным

  • один и тот же код может эволюционировать со временем, например, строка за строкой может становиться сложной и может создавать ошибки в части агрегации или наоборот

  • если в будущем вам понадобится разделить эти две процедуры, будет сложнее распутать код, который в тот момент кто-то другой написал много лет назад ...

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

Но имейте в виду, что фактор производительности может не быть проблемой в данный момент, но он может быть со временем, когда объем БД увеличится или что-то еще, это никогда не будет незначительным фактором в долгосрочной перспективе ...

0 голосов
/ 03 июня 2009

Один SQL-запрос, вероятно, является лучшей идеей. Это избавляет вас от необходимости переписывать реляционные операции

0 голосов
/ 03 июня 2009

Я не думаю, что вы вообще найдете много ситуаций, когда выполнение запроса на одну итерацию цикла является лучшим выбором. На самом деле, я бы сказал, что это, вероятно, хорошее эмпирическое правило, чтобы никогда не делал этого.

Другими словами, чем меньше обращений к базе данных, тем лучше.

В зависимости от ваших данных и фактических таблиц, вы можете позволить SQL выполнять агрегирование и выбирать все нужные вам строки одним запросом.

0 голосов
/ 03 июня 2009

Я не могу быть уверен в приведенном здесь примере, но я хотел бы знать, есть ли возможность выполнить агрегацию и другой обработки прямо в самом запросе SQL. В этом случае вам придется оценивать «более поддерживаемый» по отношению к вашему относительному уровню комфорта, выражая эту обработку в коде SQL по сравнению с кодом PHP.

Есть ли что-то дополнительное, что вам нужно сделать для каждой строки, чтобы вы не могли выразить все в самом запросе SQL?

0 голосов
/ 03 июня 2009

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

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

0 голосов
/ 03 июня 2009

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

Если бы производительность была проблемой, мой ответ был бы "не думай, профиль" . :)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...