Что обеспечивает лучшую производительность одного большого соединения или нескольких запросов? - PullRequest
25 голосов
/ 19 декабря 2009

У меня есть таблица, которая называется заказы. один столбец в заказе это customer_id
у меня есть таблица с именами клиентов с 10 полями

Учитывая два варианта, если я хочу создать массив объектов заказа и встроить его в объект заказа, это объект клиента, у меня есть два варианта.

Вариант 1:

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

это было бы что-то вроде:

 Select * from APplications

 Select * from Customer where id = 1
 Select * from Customer where id = 2
 Select * from Customer where id = 3
 Select * from Customer where id = etc . . .

Вариант 2:

а. сделать объединение на всех полях

это очевидный # 2, потому что вы делаете только один запрос против 1 + [numberOforders] запросов (может быть сотни и более)

Это было бы что-то вроде:

 Select * from Applications a, Customers c
 Innerjoin c.id = a.customerID

Мой главный вопрос: что если бы у меня было 10 других таблиц, которые были вне таблицы заказов (аналогично клиенту), где у вас был идентификатор в таблице заказов. если вы делаете один запрос, который объединяет эти 10 таблиц, или в какой-то момент это неэффективно:

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

Ответы [ 5 ]

19 голосов
/ 19 декабря 2009

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

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

Ваш вариант № 1 вряд ли будет работать хорошо из-за количества сетевых обращений (как уже упоминалось). Это иногда называют проблемой «select N + 1» - вы делаете один SELECT, чтобы получить список из N приложений, а затем делаете N SELECT в цикле, чтобы получить клиентов. Эта циклическая запись естественна для программистов приложений; но SQL работает намного лучше, когда вы работаете с целыми наборами данных одновременно.

Если опция # 2 медленная, даже при хорошей индексации, возможно, вы захотите изучить кеширование. Вы можете кэшировать в базе данных (используя сводную таблицу или материализованное / индексированное представление), в приложении (если имеется достаточно ОЗУ) или на выделенном сервере кэширования, таком как memcached. Конечно, это зависит от того, насколько актуальными должны быть результаты вашего запроса. Если все должно быть полностью обновлено, любой кэш должен обновляться всякий раз, когда обновляются базовые таблицы - это усложняется и становится менее полезным.

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

В зависимости от вашей СУБД, еще одна вещь, о которой стоит подумать, это влияние этого запроса на другие запросы, попадающие в ту же базу данных. Если ваша СУБД позволяет читателям блокировать средства записи, тогда этот запрос может помешать обновлению таблиц, если для его выполнения требуется много времени. Это было бы плохо. У Oracle нет этой проблемы, как и у SQL Server, когда он работает в режиме чтения зафиксированного снимка. Я не знаю о MySQL, хотя.

7 голосов
/ 19 декабря 2009

Если этот customer_id уникален в вашей таблице клиентов (а другие идентификаторы уникальны в других таблицах), поэтому ваш запрос возвращает только 1 строку на приложение, тогда выполнение одного SELECT, безусловно, более эффективно.

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

EDIT
Я попробовал это с Oracle PL / SQL с 50 000 приложений и 50 000 соответствующих клиентов.

Решение с выбором всего в одном запросе заняло
0.172 s

Решение с выбором каждого клиента в одном SELECT заняло
1.984 s

И это, скорее всего, ухудшается с другими клиентами или при доступе по сети.

2 голосов
/ 19 декабря 2009

Одиночное соединение должно быть быстрее по двум основным причинам.

Если вы выполняете запросы по сети, использование одного запроса вместо одного запроса приводит к дополнительным расходам.

Объединение будет оптимизировано внутри СУБД с использованием оптимизатора запросов, поэтому будет быстрее, чем выполнение нескольких запросов.

1 голос
/ 19 декабря 2009

если вы выполните один запрос, объединяющий эти 10 таблиц, или в какой-то момент он окажется неэффективным

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

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

1 голос
/ 19 декабря 2009

По моему мнению, одиночное соединение все равно будет быстрее, потому что СУБД всегда будет выполнять предложения where перед выполнением объединений. Это означает, что до того, как произойдет объединение, все соответствующие таблицы уже были сокращены до минимально возможного размера.

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

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

...