Submit Search
MySQLで論理削除と正しく付き合う方法
•
38 likes
•
80,471 views
yoku0825
Follow
2015/08/31 論理削除Casual Talks #1
Read less
Read more
1 of 34
Download now
Downloaded 64 times
More Related Content
MySQLで論理削除と正しく付き合う方法
1.
MySQLで論理削除と正しく付き合う ⽅法 2015/08/31 yoku0825 論理削除 Casual Talks
#1
2.
元のタイトルは “MySQLの論理削 除はどうして速い のか” 1/33
3.
DELETEじゃなく てUPDATEだか ら、という出落ち ネタ 2/33
4.
論理削除についてど う思うか、それぞれ の⽴場の⼈(︖)に 聞いてみました 3/33
5.
論理削除についてのそれぞれの⾒解 とある企業のDBA よく考えたら反対する理由があんまりないことに気付いた MySQL UPDATEじゃんそれ InnoDB うん、よくやるよくやる 4/33
6.
みたいな 5/33
7.
とはいえ書い てて何となく 思い当たる 6/33
8.
MySQLの都合に沿 って 論理削除すれ ば 必要悪
っぽいけ ど 7/33
9.
そうでない場 合は単なる 害 悪 8/33
10.
Using where; とか Using filesort;
の温床 9/33
11.
という訳でなんか その辺を整理して みようと思います 10/33
12.
\こんばんは/ yoku0825@とある企業のDBA オラクれない- ポスグれない- マイエスキューエる- 家に帰ると 妻の夫- せがれの⽗- ムスメの⽗- Twitter: @yoku0825 Blog: ⽇々の覚書 MyNA
ML: ⽇本MySQLユーザ会 11/33
13.
※個⼈の⾒解であり、所 属する組織あるいは所属 しない組織の意⾒を代表 するわけがありません 12/33
14.
ちょっと待て︕ そ のカラムNOT NULL制約ついて る︕︖ 13/33
15.
( ゚д゚) ハッ 14/33
16.
※個⼈の⾒解であり、所 属する組織あるいは所属 しない組織あるいは NULLの意⾒を代表する わけがありません 15/33
17.
個⼈の意⾒ 本当はしてほしくない 余計なカラムは増えて欲しくないし- 参照されないデータは⼊っていて欲しくない- テーブル設計的に汚い- 個⼈的に⼀番好きなのはDELETEトリガーでアーカイブ⽤の テーブルに追い出しちゃうこと カジュアルに元テーブルにADD COLUMNしてアーカイブ⽤のテーブ ルにADD COLUMNを忘れるとトリガーが腐ってひどいことに - 16/33
18.
よく考えること UNIQUE制約さん息してない カラムぶんデータのサイズが⼤きくなる 削除されなかったレコードがゴミとしてたまる covering index狙いにくい WHERE狙いのキーはなんとかなるかも知れないけど- ORDER BY狙いのキーでだいたい死ぬ- 17/33
19.
んー︖ UNIQUE制約さん息してない でも残念ながらナチュラルキーがしっかり定義してあるテーブルの⽅ が少ない - カラムぶんデータのサイズが⼤きくなる TINYINTなら(1バイト * レコード数)
* (1 + セカンダリーインデッ クス数) 数千万レコード8インデックスくらいならせいぜい数百メガバイト これが⼗ギガバイト単位になるなら考え直した⽅がいいかも - 18/33
20.
あれ︖ 削除されなかったレコードがゴミとしてたまる そもそもWEBサービス削除少ない- みんなだいすきtpcc-mysqlだと1/47より少ない(内部でカーソル回し てるのでSELECTもうちょっと多いはず) - deliveryの中だけで⾒て1/7 体感、もっと少ないと思う - 100GBのレコードの1%が削除されるとして1GBなら誤差範囲なんじ ゃ︖ (⼈によるかな) - covering index狙いにくい 狙いにくくはあるけどちゃんとインデックス設計してWHEREの先頭 で必ず指定するようにすれば狙っていける - 19/33
21.
前提 サロゲートキーが振られていて、他にユニーク制約がない 削除フラグのカラムはboolかせめてENUM 削除フラグのカラムは全てのセカンダリーインデックスの先 頭に振られている MySQLが5.5以降でない (ごめんなさい当⽇「5.5以降であ ること」みたいに話してましたが逆でした。。) UPDATEで済ませないといけない理由がある 削除されたデータに運営やバッチがアクセスする- ユーザートラフィックのくせに削除の対象レコードが数万規模- 20/33
22.
サロゲートキー ナチュラルキーがある場合に論理削除しちゃうとナチュラル キーで制約できない 残念ながらナチュラルキーが使われてるケースの⽅が少ない ナチュラルキー, サロゲートキーは宗教戦争になるので、ウチではサ ロゲートキーが主流なので忌避する理由にならない、とだけ⾔ってお きます - 「 サロゲートキーの毒を⾷らわば論理削除の皿まで
」って感じ- 21/33
23.
削除フラグの型 DATETIME型, TIMESTAMP型は変 NULLABLE⼤前提になる- “削除されているかどうか”というドメインと”いつ削除されたか”とい うドメインが1つのカラムで表現される - リレーショナルモデル的に間違ってる- bool型なら”= 0”で等価検索できるのでインデックスが上⼿く使える- 22/33
24.
削除 フラグ︖ というかそもそも論理 削除
とか 削除 フラグなんていうか ら話が掴みにくくなる スーパー非表⽰フラグとか表⽰ステータスとかにすればいいんじゃ ね︖ - そうすれば、それはレコードの 属性 の⼀つなので、リレーショナル モデル的に納得がいく 運営のみ閲覧可能フラグとかユーザー非表⽰フラグとかでもいい ステータスならENUM(ʻNOT̲DELETEDʼ, ʻDELETED̲BY̲USERʼ, ʻDELETED̲BECAUSE̲DMCAʼ, ʻDELETED̲BECAUSE̲PORNʼ, ..)とか︖ ただし”display̲status <> ʻNOT̲DELETEDʼ“とかやると死ねる。 とはいえそんなクエリー流すの管理画⾯だけであるべきなので、テーブルスキャンく らいは覚悟しろという気でいる。 - 23/33
25.
削除フラグのインデックス 全てのセカンダリーインデックスの先頭に削除フラグのカラ ムが存在しなければならない 本当は先頭じゃなくてもいいけど(カーディナリティー2だし)「先 頭じゃなくていい」って⾔って変なところに挟まれるくらいだったら 統⼀して先頭に「確実に」振ってほしい - 24/33
26.
削除フラグのインデックス そして全ての(ユーザートラフィックによる)クエリーは WHERE句の先頭で削除フラグのカラムを等価⽐較しなけれ ばならない たとえば”WHERE super̲hidden̲flag= 0
AND thread̲id= ? ORDER BY comment̲date DESC” なら “KEY (super̲hidden̲flag, thread̲id, comment̲date)” - AND演算⼦は等価交換できるから先頭じゃなくてもいいにしても、 super̲hidden̲flagが”=”演算⼦で評価されてないとこのインデック スは使えない だからboolがいい - というかユーザートラフィックから参照されるならそれ削除 じゃないよね 25/33
27.
UPDATEとDELETEの違い UPDATEでもDELETEでもインデックスを使ってレコードを 探す DELETEの場合、クラスターインデックスのリーフを削除するので場 合によってはリバランスが⾛る - UPDATEの場合、クラスターインデックスのリーフが書き換わる セカンダリーインデックスはチェンジバッファを使って非同期に更新される DELETEの場合は最終的に全てのセカンダリーインデックスが更新される UPDATEの場合はそのカラムが含まれるセカンダリーインデックスだけ更新される super̲hidden̲flagが全部のセカンダリーインデックスの先頭にあると最終的なI/O 量の旨味は少ない けどどうせ非同期だし意外と目をつむれる - 26/33
28.
MySQLが5.5 <del>以降</del> より前 チェンジバッファがDELETE,
UPDATEに対応するのは MySQL 5.5以降 チェンジバッファが効くとセカンダリーインデックス(プライマリ ー, ユニークはダメ)への反映が非同期になる - “DELETE確かに遅いけど、そんなに⾔うほどでもなくね︖” と思った らこれが効いているケースが多い - 27/33
29.
MySQLが5.5 <del>以降</del> より前 それ以前は
インサートバッファ (INSERTにしかセカンダ リーインデックスの非同期反映が有効でない) DELETEはクラスターインデックスと全てのセカンダリーインデック スを同期で反映させるのに対し - super̲hidden̲flagのUPDATEはクラスターインデックスはまず触ら ないし、super̲hidden̲flagを含むセカンダリーインデックスだけ反 映させればいい - UPDATEにせよDELETEにせよ、MySQL 5.5とそれ以降にすることで チェンジバッファの恩恵を受けられる - ということは別に前提ではないかも 28/33
30.
じゃあ実際どれくらい違うかっていうと 次のページのグラフ 横軸はtpcc-mysqlのdeliveryトランザクションの経過時間 基本的に、最初がバッファプールあったまってなくてだんだんあった まっていくので右に⾏くほどレイテンシーが下る - 縦軸はレイテンシー、単位はミリ秒 ⼩さければ⼩さいほどいい- DELETE, UPDATEでただカラムを⾜しただけ, UPDATEでカ ラムとインデックスを追加、の3パターン トランザクション内のステートメントは7つ、対象をSELECTして DELETEする2ステートメントが影響を受ける - 29/33
31.
微妙 super̲hidden̲flagを含めたインデックスを作らないとDELETE より遅い(やっぱりSELECTが⾜を引っ張ってる) 30/33
32.
UPDATEで済ませないといけない理由 “削除”されたデータにアクセス “削除”された理由を解析しなければならない- 利⽤規約なのか法律なのかよく知らないけど、”いつ”削除されたのか を保持しておく必要がある - 非同期でS3のファイルを消したりするから、そっちの削除が終わるま で取っておかないといけない - ユーザートラフィックなのに”削除”対象が数万レコード Kazuho@Cybozu Labs: フレンド・タイムライン処理の原理と実践- 31/33
33.
という訳で サロゲートキーの毒を⾷らわば論理削除の皿まで サロゲートキーじゃないといいことない- インデックスがちゃんと切ってあればシステム的には⾔うほ ど変わらない DELETEされたレコードの⽐率が⼗分少ない場合に限る- 論理削除じゃなくて非表⽰状態へのUPDATEなんだっ⼿⽻先 32/33
34.
Questions and/or Suggestions? Q.
インデックスの先頭にカーディナリティーの⼩さい super̲hidden̲flagを置くのは悪⼿じゃね︖ A. ちゃんと正しい位置に置いてくれるならどこでもいいんだけど、「先頭」 って⾔っておかないとだいたいひどいことになる Q. DELETEトリガーでアーカイブテーブルに追い出すののデメ リットはなんかある︖ A. トリガーはトラブルシュート⾯倒。ADD COLUMNしたらトリガーが腐っ て全部のDELETEが転けるとか。 33/33
Download