Концептуальный вопрос: быстрее ли отдельные запросы, чем объединения, или: я должен попытаться сжать каждую информацию, которую я хочу на стороне клиента, в один оператор SELECT или просто использовать столько, сколько кажется удобным?
TL; DR : если мой присоединенный запрос занимает больше времени, чем выполнение отдельных запросов, это моя ошибка или это следует ожидать?
Во-первых, я не очень разбираюсь в базе данных, так что это может быть только я, но я заметил, что, когда мне нужно получить информацию из нескольких таблиц, «часто» быстрее получить эту информацию с помощью нескольких запросов к отдельным таблицам (может быть, содержит простое внутреннее соединение) и соединяет данные вместе на стороне клиента, чтобы попытаться написать (сложный) объединенный запрос, где я могу получить все данные в одном запросе.
Я попытался собрать один чрезвычайно простой пример:
Настройка схемы :
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 |
Запрос Б :
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 «ячеек данных», потому что при объединении я естественно включаю некоторую избыточность в набор результатов.
Обобщая из этого (насколько это возможно):
Объединенный запрос всегда должен возвращать больше данных, чем отдельные запросы, которые получают одинаковое количество информации. Поскольку база данных должна объединять данные, для больших наборов данных можно предположить, что база данных должна выполнять больше работы над одним объединенным запросом, чем над отдельными, поскольку (по крайней мере) она должна возвращать больше данных клиенту.
Из этого следует, что когда я наблюдаю, что разбиение запроса на стороне клиента на несколько запросов дает лучшую производительность, это просто путь, или это скорее означает, что я испортил объединенный запрос?
Ответы:
В любом сценарии производительности вы должны протестировать и измерить решения, чтобы увидеть, какие из них быстрее .
Тем не менее, это почти всегда тот случай, когда объединенный результирующий набор из правильно настроенной базы данных будет быстрее и лучше масштабируется, чем возвращать исходные строки клиенту и затем объединять их там. В частности, если входные наборы велики, а набор результатов мал - подумайте о следующем запросе в контексте обеих стратегий: объедините две таблицы по 5 ГБ каждая с набором результатов из 100 строк. Это крайность, но ты видишь мою точку зрения.
Весьма вероятно, что схема базы данных или индексы могут быть улучшены, чтобы лучше обслуживать запросы, которые вы на нее бросаете.
Обычно это не так. В большинстве случаев, даже если входные наборы велики, набор результатов будет намного меньше, чем сумма входных данных.
В зависимости от приложения очень большие наборы результатов запроса, возвращаемые клиенту, сразу же отмечаются красным: что делает клиент с таким большим набором данных, который невозможно сделать ближе к базе данных? Весьма подозрительно, по меньшей мере, показывать пользователю 1 000 000 строк. Пропускная способность сети также является ограниченным ресурсом.
Не обязательно. Если данные проиндексированы правильно, более вероятно, что операция объединения будет выполняться более эффективно в базе данных без необходимости сканирования большого количества данных. Более того, механизмы реляционных баз данных специально оптимизированы на низком уровне для объединения ; клиентских стеков нет.
Поскольку вы сказали, что у вас нет опыта работы с базами данных, я бы посоветовал узнать больше о дизайне баз данных и настройке производительности. Я почти уверен, что здесь проблема. Неэффективно написанные SQL-запросы также возможны, но с простой схемой, которая менее вероятно, будет проблемой.
Это не значит, что нет других способов улучшить производительность. Существуют сценарии, в которых вы можете выбрать сканирование среднего или большого набора данных и вернуть его клиенту, если вы хотите использовать какой-то механизм кэширования. Кэширование может быть отличным, но оно вносит сложности в ваш дизайн. Кэширование может даже не подходить для вашего приложения.
Одна вещь, которая нигде не упоминалась, это поддержание согласованности в данных, возвращаемых из базы данных. Если используются отдельные запросы, более вероятно (из-за многих факторов) возвращать несогласованные данные, если только для каждого набора запросов не используется форма изоляции моментального снимка.
источник
Вы собрали хороший пример кода. Вы смотрели на время в SQL Fiddle? Даже некоторое краткое ненаучное тестирование производительности покажет, что запрос три в вашей демонстрации занимает примерно столько же времени, что и запрос один или два по отдельности. Объединение одного и двух занимает примерно вдвое больше трех, то есть до того, как будет выполнено любое соединение на стороне клиента.
По мере увеличения данных скорость запросов один и два будет расходиться, но соединение с базой данных все равно будет быстрее.
Также следует учитывать, что произойдет, если внутреннее объединение уничтожит данные.
источник
Оптимизатор запросов также должен быть рассмотрен. Его роль состоит в том, чтобы взять ваш декларативный SQL и перевести его на процедурные шаги. Чтобы найти наиболее эффективную комбинацию процедурных шагов, он также изучит комбинации использования индекса, сортировки, кэширования промежуточных наборов результатов и всех других вещей. Количество перестановок может быть чрезвычайно большим даже при том, что выглядит как довольно простые запросы.
Большая часть расчетов, сделанных для нахождения лучшего плана, определяется распределением данных в таблицах. Эти распределения выбираются и хранятся в виде объектов статистики. Если это не так, они приводят оптимизатор к неправильному выбору. Плохой выбор в начале плана приводит к еще худшему выбору в последствии в виде снежного кома.
Не секрет, что запрос среднего размера, возвращающий скромные объемы данных, занимает несколько минут. Правильная индексация и хорошая статистика уменьшают это до миллисекунд.
источник
Несколько запросов это путь. Если вы работаете с такими простыми сценариями - затраты на оптимизатор запросов являются фактором. При большем количестве данных возникает неэффективность объединения (избыточные строки). Эффективность достигается только при гораздо большем количестве данных.
В конце концов, то, что вы испытываете, - это то, что видят многие разработчики. Администраторы базы данных всегда говорят «нет, сделайте объединение», но реальность такова: в этом случае быстрее сделать несколько простых выборов.
источник