TableauをDjangoに移行したら、設計ミスで全部作り直しになった話
【設計が9割】
はじめに
Tableauで作っていたダッシュボードを、DjangoでWebシステムとして作り直したことがあります。
リリース直前、こうなりました。
ボタンを押してから表示まで10秒以上かかる
フィルタを変えるたびに画面が固まる
同じ画面なのに、開くたびに数字が微妙に違う
「一応動いてる。でもこれ、本番に出せないよね」
このまま修正で乗り切れないか、1週間悩みました。
クエリを軽くしたり、インデックスを貼ったり、キャッシュも試しました。
でも改善しませんでした。
そこでやっと気づきました。
これは実装じゃなくて、設計の問題だ
→ 全部作り直すことにしました。
なぜ移行したのか
・Tableauのレスポンスが遅い
・複雑なUI制御ができない
・業務フローに組み込みづらい
「Web化すれば解決する」
そう思って、Djangoで作り直しました。
最初にやった失敗
Tableauの画面をそのまま再現する
何が起きたか
「動くけど使えないもの」ができました。
SELECT
s.store_id,
SUM(s.amount),
COUNT(oi.order_id)
FROM sales s
JOIN order_items oi ON s.order_id = oi.order_id
JOIN customers c ON s.customer_id = c.id
WHERE s.sales_date BETWEEN :from AND :to
GROUP BY s.store_id;これを画面操作ごとに毎回実行していました。
どう使えなかったか
・フィルタ変更 → 毎回10秒待ち
・同時アクセス → タイムアウト
・SQLが画面ごとに違う → 修正が横に広がる
・数字がズレる → 原因が追えない
「表示はできる。でも業務で使えない」
なぜ失敗したのか
データ設計をしていなかった
やり直したこと
画面を一旦捨てて、データから作り直しました。
① データマート設計
・粒度を決める(1店舗 × 1日)
・JOINを不要にする
・集計済みテーブルを作る
CREATE TABLE sales_daily (
store_id INT,
sales_date DATE,
total_amount DECIMAL,
order_count INT,
PRIMARY KEY (store_id, sales_date)
);② ETLで事前集計
INSERT INTO sales_daily
SELECT
s.store_id,
s.sales_date,
SUM(s.amount),
COUNT(*)
FROM sales s
GROUP BY s.store_id, s.sales_date;③ Django側の簡略化
SELECT *
FROM sales_daily
WHERE sales_date BETWEEN :from AND :to;④ 役割分離
ETL:計算
DB:保持
Django:取得
画面:表示
結果
・レスポンス:10秒 → 0.5秒
・SQL:複雑 → シンプル
・修正:1箇所で完結
一番の学び
BIは見た目じゃなくてデータ設計で決まる
まとめ
今回の失敗はこれです。
再現しようとしたこと
正しい順番はこうです。
① データ設計
② データの流れ
③ バックエンド
④ 画面
おわりに
設計を外すと、ツールを変えても同じ場所で壊れます。
関連記事
・Tableauあるある事故集6選
・データマート設計でやらかす事故6選
・SQL実務テクニック6選
同じようにBIをWeb化する人は、最初にデータ設計から考えてください。
参考になったらスキもらえると励みになります。
