SparkSQL подзапрос и производительность - PullRequest
0 голосов
/ 11 ноября 2018

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

Seq("Italy", "France", "United States", "Spain").toDF("country").createOrReplaceTempView("big_countries")
Seq("Poland", "Hungary", "Spain").toDF("country").createOrReplaceTempView("medium_countries")

Количество этих словарей ограничено только воображением пользователя и потребностями бизнеса.

После этого пользователи также создают различные запросы, которые могут использовать условия на основе ранее определенных вспомогательных данных, например SQL WHERE условия:

Q1: country IN (FROM medium_countries)
Q2: (TRUE = ((country IN (FROM medium_countries)) AND (country IN (FROM big_countries))) AND EMAIL IS NOT NULL) AND phone = '+91-9111999998'
Q3: TRUE = ((country IN (FROM medium_countries)) AND (country IN (FROM big_countries))) AND EMAIL IS NOT NULL
......
Qn: name = 'Donald' AND email = 'donald@example.com' AND phone = '+1-2222222222'

Количество этих запросов ограничено только воображением пользователя и потребностями бизнеса.

Наибольшее беспокойство у меня сейчас вызывает подзапрос, подобный country IN (FROM medium_countries)

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

ОБНОВЛЕНО

Сейчас я могу проверить это только в Spark Local Mode

Запрос:

country IN (FROM big_countries)

План выполнения:

+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---+
|plan                                                                                                                                                                                                                                                                                                                                                                            |tag|
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---+
|== Physical Plan ==
*(1) Project [unique_id#27L]
+- *(1) BroadcastHashJoin [country#22], [country#3], LeftSemi, BuildRight
   :- *(1) Project [country#22, unique_id#27L]
   :  +- LocalTableScan [name#19, email#20, phone#21, country#22, unique_id#27L]
   +- BroadcastExchange HashedRelationBroadcastMode(List(input[0, string, true]))
      +- LocalTableScan [country#3]|big|
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---+

Запрос:

TRUE = ((country IN (FROM medium_countries)) AND (country IN (FROM big_countries))) AND EMAIL IS NOT NULL

План выполнения:

+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---+
|plan                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |tag|
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---+
|== Physical Plan ==
*(1) Project [unique_id#27L]
+- *(1) Filter (true = (exists#53 && exists#54))
   +- *(1) BroadcastHashJoin [country#22], [country#3], ExistenceJoin(exists#54), BuildRight
      :- *(1) BroadcastHashJoin [country#22], [country#8], ExistenceJoin(exists#53), BuildRight
      :  :- *(1) Project [country#22, unique_id#27L]
      :  :  +- *(1) Filter isnotnull(EMAIL#20)
      :  :     +- LocalTableScan [name#19, email#20, phone#21, country#22, unique_id#27L]
      :  +- BroadcastExchange HashedRelationBroadcastMode(List(input[0, string, true]))
      :     +- LocalTableScan [country#8]
      +- BroadcastExchange HashedRelationBroadcastMode(List(input[0, string, true]))
         +- LocalTableScan [country#3]|big|
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---+

1 Ответ

0 голосов
/ 12 ноября 2018

Я думаю, что:

CACHE TABLE tbl  as in sql("CACHE TABLE tbl")

- это то, что вам нужно выполнить после:

...createOrReplaceTempView....

но перед большими запросами, конечно.

В SPARK вышеприведенное утверждение о «кешировании» теперь по умолчанию нетерпеливое, а не ленивое. Как указано в руководстве, вам больше не нужно запускать материализацию кэша вручную. То есть больше не нужно выполнять df.show или df.count.

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

Не зная вашего дизайна, но глядя на него, подзапрос должен быть в порядке. Попробуйте этот подход и посмотрите на физический план. В традиционных СУБД этот тип ограниченного подзапроса, как я вижу, также не является нарушителем условий сделки.

Вы также можете видеть, что в Физическом плане показано, что Catalyst Optimizer уже оптимизировал / преобразовал ваш подзапрос IN в JOIN, что является типичным улучшением производительности для больших наборов данных.

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

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