見出し画像

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化する人は、最初にデータ設計から考えてください。

参考になったらスキもらえると励みになります。

いいなと思ったら応援しよう!