Оптимизация производительности объединения с таблицей разделов Hive - PullRequest
2 голосов
/ 08 июля 2019

У меня есть таблица Hive orc test_dev_db.TransactionUpdateTable с некоторыми примерами данных, которая будет содержать данные приращения, которые необходимо обновить в основную таблицу (test_dev_db.TransactionMainHistoryTable), которая разбита на столбцы Country, Tran_date.

Hive Схема таблицы инкрементальной загрузки: она содержит 19 строк, которые необходимо объединить.

CREATE TABLE IF NOT EXISTS test_dev_db.TransactionUpdateTable 
(
Transaction_date timestamp,
Product       string,
Price         int,
Payment_Type  string,
Name          string, 
City          string,
State         string,
Country       string
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
STORED AS orc
;

Схема основной таблицы Hive: общее количество строк 77.

CREATE TABLE IF NOT EXISTS test_dev_db.TransactionMainHistoryTable
(
Transaction_date timestamp,
Product       string,
Price         int,
Payment_Type  string,
Name          string,
City          string,
State         string
)
PARTITIONED BY (Country string,Tran_date string) 
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
STORED AS orc
;

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

SELECT
  case when i.transaction_date is not null then cast(substring(current_timestamp(),0,19) as timestamp)  
  else t.transaction_date   end as transaction_date,
  t.product,
  case when i.price is not null then i.price else t.price end as price,
  t.payment_type,
  t.name,
  t.city,
  t.state,
  t.country,
  case when i.transaction_date is not null then substring(current_timestamp(),0,10) 
  else t.tran_date end as tran_date
  from
test_dev_db.TransactionMainHistoryTable t
full join test_dev_db.TransactionUpdateTable i on (t.Name=i.Name)
;
/hdfs/path/database/test_dev_db.db/transactionmainhistorytable/country=Australia/tran_date=2009-03-01
/hdfs/path/database/test_dev_db.db/transactionmainhistorytable/country=Australia/tran_date=2009-05-01

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

SELECT
  case when i.transaction_date is not null then cast(substring(current_timestamp(),0,19) as timestamp)  
  else t.transaction_date   end as transaction_date,
  t.product,
  case when i.price is not null then i.price else t.price end as price,
  t.payment_type,
  t.name,
  t.city,
  t.state,
  t.country,
  case when i.transaction_date is not null then substring(current_timestamp(),0,10) else t.tran_date end as tran_date
  from
(SELECT 
  *
  FROM 
test_dev_db.TransactionMainHistoryTable
where Tran_date in
(select distinct  from_unixtime(to_unix_timestamp (Transaction_date,'yyyy-MM-dd HH:mm'),'yyyy-MM-dd') from test_dev_db.TransactionUpdateTable
))t
full join test_dev_db.TransactionUpdateTable i on (t.Name=i.Name)
;

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

План выполнения для секционированной таблицы как:

 Stage: Stage-5
    Map Reduce
      Map Operator Tree:
          TableScan
            alias: transactionmainhistorytable
            filterExpr: tran_date is not null (type: boolean)
            Statistics: Num rows: 77 Data size: 39151 Basic stats: COMPLETE Column stats: COMPLETE
            Map Join Operator
              condition map:
                   Left Semi Join 0 to 1
              keys:
                0 tran_date (type: string)
                1 _col0 (type: string)
              outputColumnNames: _col0, _col1, _col2, _col3, _col4, _col5, _col6, _col7, _col8

Я что-то не так делаю со вторым запросом? Нужно ли использовать оба раздела столбца для лучшего сокращения. Любая помощь или совет с благодарностью.

1 Ответ

1 голос
/ 08 июля 2019

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

where tran_date IN (select ... )

фактически совпадает с

LEFT SEMI JOIN (SELECT ...)

И это отражено в плане:

Map Join Operator
              condition map:
                   Left Semi Join 0 to 1
              keys:
                0 tran_date (type: string)
                1 _col0 (type: string) 

И это выполняется как map-join.Сначала выбирается набор данных подзапроса, затем он помещается в распределенный кеш, загружается в память для использования в map-join.Все эти шаги: select, загрузка в память, map-join выполняются медленнее, чем чтение, и перезаписывают всю таблицу, потому что она настолько мала и перегружена: статистика показывает Num строк: 77 Размер данных: 39151 - слишком мал для разбиения на двастолбцы и даже слишком малы, чтобы быть разделеннымиПопробуйте таблицу большего размера и используйте EXPLAIN EXTENDED, чтобы проверить, что в действительности сканируется.

Также замените это:

from_unixtime(to_unix_timestamp (Transaction_date,'yyyy-MM-dd HH:mm'),'yyyy-MM-dd')

на substr(Transaction_date,0,10) или date(Transaction_date)

Иsubstring(current_timestamp,0,10) с current_date, чтобы немного упростить код.

Если вы хотите, чтобы в разделе отображался фильтр разделов, попробуйте заменить фильтр разделов, переданный в виде списка разделов, который вы можете выбрать в отдельном сеансе.и используйте shell для передачи списка разделов в предложение where, смотрите ответ: https://stackoverflow.com/a/56963448/2700344

...