Подтвердить что ты не робот

Почему вы предпочитаете Java 8 Stream API вместо прямых запросов на спящий режим /sql при работе с БД

В последнее время я вижу много кода в нескольких проектах, использующих поток для фильтрации объектов, например:

library.stream()
          .map(book -> book.getAuthor())
          .filter(author -> author.getAge() >= 50)
          .map(Author::getSurname)
          .map(String::toUpperCase)
          .distinct()
          .limit(15)
          .collect(toList()));

Есть ли преимущества использования этого вместо прямого запроса HQL/SQL в базу данных, возвращающую уже отфильтрованные результаты.

Разве не второй aproach гораздо быстрее?

4b9b3361

Ответ 1

Если данные изначально поступают из БД, лучше делать фильтрацию в БД, а не извлекать все и локально фильтровать.

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

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

Ответ 2

На первый взгляд: потоки могут выполняться параллельно; просто, изменив код для использования parallelStream(). (отказ от ответственности: конечно, это зависит от конкретного контекста, если просто изменение типа потока приведет к правильным результатам, но да, это может быть так просто).

Затем: потоки "приглашают" использовать лямбда-выражения. А те, в свою очередь, приводят к использованию инструкций invoke_dynamic bytecode; иногда получая преимущества по сравнению с "старой школьной" формой написания такого кода. (и для разъяснения недоразумений: invoke_dynamic - свойство lambdas, а не потоков!)

Это были бы предпосылки предпочитать "потоковые" решения в настоящее время (с общей точки зрения).

Помимо этого: это действительно зависит... давайте посмотрим на ваш пример ввода. Это похоже на работу с обычными Java POJO, которые уже находятся в памяти, в какой-то коллекции. Обработка таких объектов в памяти напрямую будет определенно быстрее, чем переход в некоторую базу данных вне процесса, чтобы там работать!

Но, конечно: когда вышеупомянутые вызовы, например book.getAuthor(), будут делать "глубокое погружение" и фактически разговаривают с базовой базой данных; то вероятность того, что "все это в одном запросе" даст вам лучшую производительность.

Ответ 3

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

Имея это в виду, есть много причин, по которым используются потоковые API.

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

  2. Если что-то похожее в первом абзаце используется, это на самом деле создает хороший DSL для построения ваших запросов. Scalas Slick и .Net LINQ, где ранние примеры, о которых я знаю, хотя я предполагаю, что кто-то создал что-то подобное в LISP задолго до моего рождения.

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

  4. Им приятнее читать императивный код. Может быть, обработка, выполненная в потоке, [легко/автором] не может быть выполнена с помощью SQL. Таким образом, альтернативы - это не SQL против Java (или того языка, который вы используете), а императивная Java или "функциональная" Java. Позднее часто читает лучше.

Так что есть веские причины использовать такой API.

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

Ответ 4

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

DB может обрабатывать гораздо большие данные, а затем ваш java-процесс

Запросы в базе данных можно индексировать (сделать их намного быстрее)

С другой стороны, если ваши данные малы, используя Stream, то, как вы это сделали, является эффективным. Запись такого потокового конвейера очень читаема (как только вы достаточно хорошо говорите о потоках).

Ответ 5

Ну, ваш вопрос в идеале должен быть Лучше ли делать операции сокращения/фильтрации в БД или извлекать все записи и делать это в Java с помощью Streams?

Ответ не прост, и любые статистические данные, которые дают "конкретный" ответ, не будут обобщаться на все случаи.

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

Один случай, когда я предпочел бы фильтровать данные в Java-коде, а не в БД, - это если вам нужно отфильтровать разные функции из одних и тех же данных. Например, прямо сейчас вы получаете только фамилию автора. Если вы хотите получить все книги, написанные автором, возраст авторов, детей автора, место рождения и т.д. Тогда имеет смысл получить только одну копию "только для чтения" из БД и использовать параллельные потоки для получения различной информации из того же набора данных.

Ответ 6

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

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

Ответ 7

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

ОП спросил, "Есть ли какие-либо преимущества использования этого вместо прямого запроса HQL/SQL к базе данных, возвращающей уже отфильтрованные результаты".

Поэтому, если кто-то пишет, а затем выполняет запрос, используя PreparedStatement со всеми соответствующими предложениями, например, WHERE age> = 50, разве это не пример того, как БД выполняет фильтрацию, а не локальную фильтрацию? т.е. набор результатов будет содержать только те строки, где age> = 50, no?