Являются ли индивидуальные запросы быстрее, чем объединяются?

Концептуальный вопрос: Являются ли индивидуальные запросы быстрее, чем присоединяются, или: Должен ли я пытаться сжать каждую информацию, которую я хочу на стороне клиента, в инструкцию SELECT один или просто использовать столько, сколько кажется удобным

TL; DR . Если присоединенный запрос my занимает больше времени, чем запуск отдельных запросов, это моя ошибка или это можно ожидать?

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

Я попытался объединить один очень простой пример:

скрипт SQL

Настройка схемы :

CREATE TABLE MASTER 
( ID INT NOT NULL
, NAME VARCHAR2(42 CHAR) NOT NULL
, CONSTRAINT PK_MASTER PRIMARY KEY (ID)
);

CREATE TABLE DATA
( ID INT NOT NULL
, MASTER_ID INT NOT NULL
, VALUE NUMBER
, CONSTRAINT PK_DATA PRIMARY KEY (ID)
, CONSTRAINT FK_DATA_MASTER FOREIGN KEY (MASTER_ID) REFERENCES MASTER (ID)
);

INSERT INTO MASTER values (1, 'One');
INSERT INTO MASTER values (2, 'Two');
INSERT INTO MASTER values (3, 'Three');

CREATE SEQUENCE SEQ_DATA_ID;

INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.3);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.5);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.7);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 2, 2.3);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 3, 3.14);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 3, 3.7);

Запрос A :

select NAME from MASTER
where ID = 1

Результаты :

| NAME |
--------
|  One |

Запрос B :

select ID, VALUE from DATA
where MASTER_ID = 1

Результаты :

| ID | VALUE |
--------------
|  1 |   1.3 |
|  2 |   1.5 |
|  3 |   1.7 |

Запрос C :

select M.NAME, D.ID, D.VALUE 
from MASTER M INNER JOIN DATA D ON M.ID=D.MASTER_ID
where M.ID = 1

Результаты :

| NAME | ID | VALUE |
---------------------
|  One |  1 |   1.3 |
|  One |  2 |   1.5 |
|  One |  3 |   1.7 |

Конечно, я не оценивал их с такой производительностью, но можно заметить:

  • Запрос A + B возвращает то же количество полезной информации, что и запрос C.
  • A + B должен вернуть клиенту 1 + 2x3 == 7 "Ячейки данных"
  • C должен вернуть клиенту 3x3 == 9 «Ячейки данных», потому что с присоединением я, естественно, включаю некоторую избыточность в результирующем наборе.

Обобщая это (насколько это возможно):

Объединенный запрос always должен возвращать больше данных, чем отдельные запросы, которые получают одинаковое количество информации. Поскольку база данных должна собирать данные, для больших наборов данных , можно предположить, что база данных должна работать больше на одном объединенном запросе, чем на отдельных, поскольку (по крайней мере) она должна вернуть клиенту дополнительные данные.

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

36 голосов | спросил Martin 24 Maypm13 2013, 18:23:44

4 ответа


39
  

Являются ли индивидуальные запросы быстрее, чем объединения, или: следует ли пытаться сжать каждую информацию, которую я хочу на стороне клиента, в один оператор SELECT или просто использовать столько, сколько кажется удобным?

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

Тем не менее, почти всегда бывает, что объединенный результирующий набор из правильно настроенной базы данных будет быстрее и масштабироваться лучше, чем возвращать исходные строки клиенту, а затем присоединяться к ним там. В частности, если входные наборы велики и набор результатов мал - подумайте о следующем запросе в контексте обеих стратегий: объедините две таблицы, каждая по 5 ГБ, с набором результатов из 100 строк. Это крайность, но вы видите мою мысль.

  

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

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

  

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

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

В зависимости от приложения очень большие наборы результатов запроса, возвращаемые клиенту, являются кратковременным красным флажком: что делает клиент с таким большим набором данных, который нельзя сделать ближе к базе данных? Отображение 1 000 000 строк пользователю очень маловероятно. Полоса пропускания сети также является конечным ресурсом.

  

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

Не обязательно. Если данные индексируются правильно, операция соединения более эффективно выполняется в базе данных без необходимости сканирования большого количества данных. Кроме того, реляционные СУБД специально оптимизированы на низком уровне для объединения ; клиентских стеков нет.

  

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

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

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

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

ответил Jon Seigel 24 Maypm13 2013, 21:56:06
5
  

Конечно, я не измерял производительность с помощью этих

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

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

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

ответил Leigh Riffel 24 Maypm13 2013, 23:20:25
1

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

Большая часть расчетов, выполненных для поиска наилучшего плана, определяется распределением данных в таблицах. Эти дистрибутивы отбираются и сохраняются как объекты статистики. Если они ошибочны, они приводят оптимизатора к неправильному выбору. Плохой выбор на раннем этапе плана приводит к еще более плохим выборам в результате эффекта снежного кома.

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

ответил Michael Green 11 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 11 Sep 2015 06:16:54 +0300 2015, 06:16:54
-3

Несколько запросов - это путь. Если вы справляетесь с такими простыми сценариями - фактор затрат на оптимизатор запросов является фактором. С большим количеством данных появляется сетевая неэффективность соединения (избыточные строки). Только с гораздо большим количеством данных есть эффективность.

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

ответил TomTom 24 Maypm13 2013, 19:04:36

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132