Upgrade to Pro — share decks privately, control downloads, hide ads and more …

updated_at に依存したら大変なことになった / Don't depend on updated_at

megane42
November 28, 2019

updated_at に依存したら大変なことになった / Don't depend on updated_at

megane42

November 28, 2019
Tweet

More Decks by megane42

Other Decks in Programming

Transcript

  1. create_table "entries" do |t| # ... t.bigint "campaign_id", null: false

    t.string "lottery_status", default: "fresh" t.datetime "created_at", null: false t.datetime "updated_at", null: false # ... end
  2. class Entry # ... enum lottery_status: [ :fresh, :winner, :loser

    ] def draw! 抽選処理 ? winner! : loser! end def self.daily_drawers group("DATE(updated_at)").count end # ... end
  3. 当時の実装 抽選を回すと entry の updated_at が更新される 逆に、それ以外に更新される機会はない じゃあ updated_at を使って

    ⽇ごとの抽選者数 を集計しよう 後述しますが、 これ⾃体はしくじりじゃない と思ってます
  4. +---------+----------------+---------------------+---------------------+ | id | lottery_status | created_at | updated_at |

    +---------+----------------+---------------------+---------------------+ | 5 | winner | 2017-08-04 02:37:51 | 2018-09-26 01:53:54 | | 20 | winner | 2017-08-04 12:55:04 | 2018-09-26 01:53:54 | | 42 | winner | 2017-08-04 13:57:21 | 2018-09-26 01:53:54 | | 50 | winner | 2017-08-04 14:07:08 | 2018-09-26 01:53:54 | | 93 | winner | 2017-08-04 14:55:32 | 2018-09-26 01:53:54 | | 109 | winner | 2017-08-04 15:08:01 | 2018-09-26 01:53:54 | | 121 | winner | 2017-08-04 15:18:09 | 2018-09-26 01:53:54 | | 137 | winner | 2017-08-04 15:28:05 | 2018-09-26 01:53:54 | | 147 | winner | 2017-08-04 15:36:19 | 2018-09-26 01:53:54 | | 177 | winner | 2017-08-04 15:56:18 | 2018-09-26 01:53:54 |
  5. class Entry # ... def draw! + transaction do 抽選処理

    ? winner! : loser! + update!(drawed_at: Time.zone.now) + end end # ... end
  6. トレードオフ もし drawed_at を⽤意するなら: 抽選処理の実装時に、 drawed_at を埋める処理を忘れずに書く必 要がある データ遡及メンテのときは、何も考えなくてよい else

    ( updated_at に依存するなら): 抽選処理の実装時には、何も考えなくてよい データ遡及メンテのときに、 updated_at を更新してしまわない か気にする必要がある
  7. nullable なカラムを追加している最中でも INSERT できる (Aurora (MySQL)) MySQL にはオンライン DDL という機能があり、ALTER

    TABLE 中 に更新系のクエリが実⾏できる https://dev.mysql.com/doc/refman/5.7/en/innodb-online-ddl- operations.html MySQL 互換をうたっている Aurora は、その辺も互換性あるの? やってみたら追加できた !!! 必ずご⾃⾝の環境でも確認してください !!!
  8. テーブル全体を UPDATE したら徐々にロック された (Aurora (MySQL)) UPDATE entries SET drawed_at

    = created_at WHERE entries.drawed_at IS NULL 上記の SQL を実⾏すると、 entries テーブルが ID : 1 から徐々にロ ックされていった 更新ができないだけでレコード新規追加はできる 対象レコードを「ID 1 から 100 万まで」のように絞りながら⼩刻み に実⾏していくことで、影響を最⼩化できる !!! 必ずご⾃⾝の環境でも確認してください !!!