Tableau リレーションシップの説明(2023/12/16実施の勉強会)
DATASaberBridgeの雑談スレッドで、
「リレーションシップの事を教えてくれる人募集!」
という書き込みがあり、面白そうだったので手を挙げて勉強会を開催しました!
その時の内容をまとめます。
大事なポイント
Tableau内の処理を理解すること
結合、リレーションシップ、Fixed計算などが、どのような処理をしているか把握すると、理解しやすくなる。
Tableauの処理を理解するために、Excelを使って処理を再現する方法がオススメ。検算もできるようになる。
使うデータ
サンプルスーパーストアに都道府県別の人口のシートを追加したExcelを使います。
人口が多いと売上が上がりやすい傾向があるため、人口に対してどれぐらいの売上が取れているか、都道府県別に出すことが目的です。
人口データは以下のURLからコピペしました。
結合
最初に結合から始めます。都道府県をキーにして結合します。
![](https://assets.st-note.com/img/1703352415136-u2JNSvvdXc.png?width=1200)
この処理をExcelで再現すると、注文のシートの都道府県をキーに、都道府県別人口をVlookupする動きと同じです。
![](https://assets.st-note.com/img/1703352693130-kaQtMC0NR2.png?width=1200)
このデータの持ち方をすると、人口を合計したときに重複することがイメージしやすいと思います。
Tableauで都道府県別に売上と結合した人口を合計した数字です。
![](https://assets.st-note.com/img/1703352902376-cXd5xjmWwW.png?width=1200)
これを防ぐためには都道府県別の人口の最大値を取るようにすればOKです。
Fixed計算で重複をなくす
重複をなくすためにFixed計算で都道府県別の人口を取得します。
{fixed [都道府県]:MAX([人口])}
集計すると都道府県別の人口が表示されていることが分かります。
![](https://assets.st-note.com/img/1703353236480-Vu6Ajbc4Ls.png?width=1200)
正しい人口データが表示されたことが確認できたので、当初の目的の 売上 / 人口 の計算式を作ります。
sum([売上]) / sum({fixed [都道府県]:MAX([人口])})
以下は集計結果です。大分県は人口が少ない割に売上が高いことが分かります。
![](https://assets.st-note.com/img/1703353459509-ZXJoNAZk59.png?width=1200)
Fixed計算のTableau内での処理を調べる
では、Tableauの内部的な処理はどうなっているかを調べます。
[ヘルプ] → [設定とパフォーマンス] → [パフォーマンスの記録を開始]を選択し、調べたい処理を行った後に
[ヘルプ] → [設定とパフォーマンス] → [パフォーマンスの記録を停止]を選択し、結果が表示されるのを待ちます。
![](https://assets.st-note.com/img/1703353594900-D6An15cSTQ.png?width=1200)
パフォーマンスを記録する場合、同じ計算を行うとキャッシュを拾ってきて正しく測定されない場合があります。
この場合、日付やカテゴリなどのフィルタを変更し、今までに実施したことのない処理を行い、パフォーマンスを記録します。
以下はパフォーマンスの記録の結果です。
![](https://assets.st-note.com/img/1703353860268-2AciDSutQD.png?width=1200)
グラフの緑色がクエリを実行した処理速度です。
この緑の棒をクリックし、下段の Query を右クリック → コピー → データ でコピーします。
![](https://assets.st-note.com/img/1703353980934-LILSKrXjrn.png?width=1200)
以下はクエリの実行結果です。
Command
"SELECT ""t1"".""__measure__0"" AS ""TEMP({fixed 都道府県:max(人口)} (コピー)_1938799675850891267)(201083708)(0)"",
""t0"".""TEMP({fixed 都道府県:max(人口)} (コピー)_1938799675850891267)(4253624404)(0)"" AS ""TEMP({fixed 都道府県:max(人口)} (コピー)_1938799675850891267)(4253624404)(0)"",
""t0"".""都道府県"" AS ""都道府県""
FROM (
SELECT ""注文"".""都道府県"" AS ""都道府県"",
SUM(""注文"".""売上"") AS ""TEMP({fixed 都道府県:max(人口)} (コピー)_1938799675850891267)(4253624404)(0)""
FROM ""TableauTemp"".""注文$"" ""注文""
LEFT JOIN ""TableauTemp"".""都道府県別人口$"" ""都道府県別人口"" ON (""注文"".""人口"" = ""都道府県別人口"".""人口"")
WHERE (CAST(TRUNC(EXTRACT(YEAR FROM ""注文"".""オーダー日"")) AS BIGINT OR NULL) = 2023)
GROUP BY 1
) ""t0""
INNER JOIN ( //この括弧の中がFixedの計算
SELECT ""注文"".""都道府県"" AS ""都道府県"",
MAX(""注文"".""人口"") AS ""__measure__0""
FROM ""TableauTemp"".""注文$"" ""注文""
GROUP BY 1
) ""t1"" ON (""t0"".""都道府県"" IS NOT DISTINCT FROM ""t1"".""都道府県"")"
これを見ると、INNER JOINしている括弧のところが、都道府県でGroup byし、maxの人口を取っていることが分かります。
(SQLが分からないと読めないですが、ご了承ください)
これがFixed計算の正体です。LODの計算はサブクエリを作ってJOINしています。
Excelだと次のような動きをします。
![](https://assets.st-note.com/img/1703355632946-tB74XW6okX.png?width=1200)
これがExcel上で再現できるようになれば、結合やFixedが理解しやすくなります。
Tableauはよくできたツールなので、適当に書いた計算式でも数字が出て、間違った数字が出ていても気付きづらいです。
間違った数字を出さないために、検算が必須です。
私は1ステップごとにExcelで処理を行い、同じ結果がTableauで出るかどうか確認するようにしています。(大量データの場合は一部サンプルデータを抜き出して確認します。)
これをやるのは大変ですが、間違った数字を出すと信用を失う可能性があるので、必ず検算しましょう!
Fixedを使わずmaxだとどうなる?
この計算はFixedを使わなくてもmaxを使えば対応できるのでは?という質問があるかもしれません。
ディメンションに都道府県がある場合は問題ありませんが、都道府県が無い場合は全都道府県の中での最大値を取ってくるので、日本全体の人口ではなく東京都の人口で計算します。
![](https://assets.st-note.com/img/1703355419897-mpdiJmTnMS.png?width=1200)
これをExcelで再現すると以下のようになります。
![](https://assets.st-note.com/img/1703355668633-k9cPcmq0af.png?width=1200)
![](https://assets.st-note.com/img/1703355777434-BV9XMU1JBi.png)
このようなミスは起きやすいので、Fixedを使うと有効です。
また、必ず検算しましょう!
リレーションシップ
次はリレーションシップです。Excelで注文テーブルと都道府県別人口テーブルを都道府県で繋ぎます。
![](https://assets.st-note.com/img/1703355012767-C5kAclJ4M9.png?width=1200)
今回は触れませんが「パフォーマンスオプション」を設定することで速度を改善できる場合があります。(私も細かくは調べきれてないので、調べてから結果を共有します)
繋いだあとに都道府県別の売上と人口を合計で計算します。
![](https://assets.st-note.com/img/1703355172323-rOc5uBOGjS.png?width=1200)
今度は人口を合計しても重複しません!
これがリレーションシップの便利なところです。売上/人口の計算も
sum([売上])/sum([人口])
これでOKです。
結合ではテーブルを1つに結合しますが、リレーションシップでは別々のテーブルとして持ち、集計した結果をjoinします。
これが結合との違いです。
パフォーマンスの記録でこの処理の中身を見てみましょう。
Command
"SELECT SUM(""注文_64240F1E9E064A36AADE36C2487D7186"".""売上"") AS ""TEMP(Calculation_835417764500492291)(4253624404)(0)"",
""注文_64240F1E9E064A36AADE36C2487D7186"".""都道府県"" AS ""都道府県""
FROM ""Extract"".""注文_64240F1E9E064A36AADE36C2487D7186"" ""注文_64240F1E9E064A36AADE36C2487D7186""
GROUP BY 2
WHERE (CAST(TRUNC(EXTRACT(YEAR FROM ""注文_64240F1E9E064A36AADE36C2487D7186"".""出荷日"")) AS BIGINT OR NULL) = 2023)"
Command
"SELECT SUM(""都道府県別人口_0AB30B9D23DF4EDA9702D16E4538B421"".""人口"") AS ""TEMP(Calculation_835417764500492291)(3704074455)(0)"",
""都道府県別人口_0AB30B9D23DF4EDA9702D16E4538B421"".""都道府県"" AS ""都道府県""
FROM ""Extract"".""都道府県別人口_0AB30B9D23DF4EDA9702D16E4538B421"" ""都道府県別人口_0AB30B9D23DF4EDA9702D16E4538B421""
WHERE EXISTS (
SELECT 1 AS ""one""
FROM (
SELECT ""都道府県別人口_0AB30B9D23DF4EDA9702D16E4538B421"".""都道府県"" AS ""都道府県""
FROM ""Extract"".""都道府県別人口_0AB30B9D23DF4EDA9702D16E4538B421"" ""都道府県別人口_0AB30B9D23DF4EDA9702D16E4538B421""
INNER JOIN ""Extract"".""注文_64240F1E9E064A36AADE36C2487D7186"" ""注文_64240F1E9E064A36AADE36C2487D7186"" ON (""都道府県別人口_0AB30B9D23DF4EDA9702D16E4538B421"".""都道府県"" = ""注文_64240F1E9E064A36AADE36C2487D7186"".""都道府県"")
WHERE (CAST(TRUNC(EXTRACT(YEAR FROM ""注文_64240F1E9E064A36AADE36C2487D7186"".""出荷日"")) AS BIGINT OR NULL) = 2023)
GROUP BY 1
) ""t0""
WHERE (""都道府県別人口_0AB30B9D23DF4EDA9702D16E4538B421"".""都道府県"" = ""t0"".""都道府県"")
)
GROUP BY 2"
リレーションシップの場合、クエリが分かれています。
上のクエリは売上の集計、下のクエリは人口の集計をしています。
2つの集計結果をjoinするクエリは見当たらなかったので、クエリではなくTableauの内部処理で結合している可能性があります。
リレーションシップの動作タイミング
クエリパイプラインの中で、リレーションシップはデータソースフィルターとコンテキストフィルターの間で動きます。
![](https://assets.st-note.com/img/1703430074499-GxUQgIfFro.png?width=1200)
500万件ぐらいのデータをリレーションシップで自己結合して併売分析しようとしたとき、重たくて結果が出るのに10分以上かかる場合がありました。
これを改善するために、データソースフィルターを使って先にデータ量を減らすとリレーションシップのjoinが減り、速度が速くなるとTableauから回答がありました。
実際、これを実行すると速度が改善しました。リレーションシップで動作が重たい場合、データソースフィルターを設定してみてください。
(先にパフォーマンスオプションの設定を確認ください)
データソースフィルターを設定する場合、2つのテーブルの両方に条件を設定するデータソースフィルターではなく、1つずつのテーブルに対しデータソースフィルターを設定してください。
×[Tab1.date] = 2023 and [Tab2.date] = 2023
(二つのテーブルを指定するとリレーションシップが発生する)
〇[Tab1.date] = 2023
[Tab2.date] = 2023
(別々のテーブルでデータソースフィルターを指定するとリレーションシップが発生しない)
結合・リレーションシップ・ブレンドのどれを使えばいいのか?
リレーションシップ・結合・ブレンドの違いをChatGPTにまとめてもらった図です。
![](https://assets.st-note.com/img/1703428797555-yrp9m0UE6c.png?width=1200)
勉強会の時に多かった質問は、リレーションシップと結合は同じような動きだけど、どっちを使えばいいの?というものでした。
ブレンドを使う場合
私の経験から、ブレンドを使う例は以下の場合です。
パブリッシュ済みのデータソースを使用し、リレーションシップが設定されていない場合。
Tableau Prepからパブリッシュする場合はリレーションシップを設定できない。
複数テーブルの接続で、パラメータを使って動的に変化させるカラムで繋ぎたい場合。
リレーションシップの接続にはパラメータを使用することができない。
基本的には結合とリレーションシップがあれば事足りますが、状況によってはブレンドを使わないと実現できない場合があります。
例えばデータソース単位で閲覧できる範囲を設定したい場合、リレーションシップだと設定ができないため別のデータソースとしてパブリッシュする必用があります。
しかし、ブレンドの設定はやや難しいので間違いやすいので、あまりオススメしません。
結合を使う場合
結合はSQLに慣れている人には構造が分かりやすいです。
私はDB側でviewが作成できる場合、Tableauがわで接続の設定をせず、DB側でviewを作成して抽出する場合が多いです。
(複雑な接続条件をTableau側で設定すると抽出の処理が重たくなる場合があるため)
また、SQLに慣れている人が多い場合はメンテナンスがしやすくなります。
複数の人が使う場合はメンテナンス性も重要になります。
リレーションシップを使う場合
データの重複を簡単に避けたい場合はリレーションシップが有効です。
また、データ量が多い場合や自己結合をする場合はリレーションシップがオススメです。
結合するとデータ量が多くなり、DB側への負荷が高くなる場合があります。
まとめ
結合・リレーションシップ・ブレンドのどれを使うとしても、数字の確認は必須。Excelで動きを再現し、確認できるようにする。そうするとTableauの理解も深まり一石二鳥。
どの接続を使うかはケースバイケース。それぞれの特徴を理解したうえで、都度ベストな選択ができるようになるのが理想。
リレーションシップはTableau2020.2から出た機能で、今後も機能改善があるかもしれません。都度最新の情報を取得してください。
ご覧いただきありがとうございました!
質問などあればTwitterにお願いします!
https://twitter.com/Seiji_Suna