5
0

More than 3 years have passed since last update.

複合主キーのテーブルをSqoopで並列転送する

Last updated at Posted at 2020-12-21

はじめに

この記事は MicroAd Advent Calendar 2020 22日目の記事です。  
業務でApache Sqoopを使って複合主キーのテーブルを転送する際に工夫したことを記事にします。

状況設定

やりたかったことは以下の通りです。

  • レコード数が多いMySQLのテーブルをCDHに転送する
  • レコード数が多いため、レコードを分割して並列に転送しないとメモリエラーで落ちてしまう
  • MySQLのテーブルは複合主キー

MySQLの主キーが一つだったら非常に話は簡単です。 --split-byオプションに主キーを設定し、並列したい数を --num-mappersオプションに設定すれば均等に分割されて転送されます。

一方で複合主キーだった場合には --split-byオプションに複数カラムを設定することができないため、工夫が必要となります。複合主キーとは別のカラムを設定することもできますが、均等に分割されないことが予想されます。うまく転送できないかもしれません。

なお使用しているSqoopのバージョンは1.4.6です。
参考: Sqoop User Guide (v1.4.6)

解決方法

複合主キーを結合後にmd5で変換し、桁数を減らして10進数に戻したものを--split-byオプションに設定しました。
具体的には複合主キーをkey1、key2として以下のように変換された値を使用します。

CAST(CONV(LEFT(MD5(CONCAT(key1, key2)), 7), 16, 10) AS UNSIGNED)

これだけだと分かりにくいので、内側から順に確認します。

第一工程

CONCAT(key1, key2)

複合主キーを結合した文字列を作成します。

第二工程

MD5(CONCAT(key1, key2))

結合した文字列をmd5でハッシュ化します。
ハッシュ値は概ねランダムで与えられます(少なくとも検証した範囲ではほぼランダムでした)。

第三工程

LEFT(MD5(CONCAT(key1, key2)), 7)

ハッシュ値の上から7桁を取得します。
md5で変換された32桁の16進数をそのまま10進数に戻してMySQLで扱った場合、桁数が大きすぎてうまく扱えません。

第四工程

CONV(LEFT(MD5(CONCAT(key1, key2)), 7), 16, 10)

16進数を10進数に変換します。

第五工程

CAST(CONV(LEFT(MD5(CONCAT(key1, key2)), 7), 16, 10) AS UNSIGNED)

UNSIGNEDのINT型にCASTします。

最後に

この方法だと主キーがどの型か、いくつあるか等を気にする必要がありません。パフォーマンスも良好で、レコードが数千万件に上るMySQLのテーブルも上手く分割され、並列に転送されるようになりました。
他にも上手く転送する方法がありましたら、教えていただけると幸いです。

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0