「スッキリわかるSQL入門」読書会レポート vol.8

株式会社リゾーム 技術部 システム開発 第3グループの土井です。 「スッキリわかるSQL入門」読書会の第8回レポートです。
「スッキリわかるSQL入門」の過去のレポートや他の読書会のレポートはこちらからご覧いただけます。

tech.rhizome-e.com

読書会の題材

前回までに引き続き「スッキリわかるSQL入門」を題材としています。

8回目レポート

8回目は第9章「トランザクション」のレポートになります。参加者は5名でした。

それぞれの感想・意見交換

正確なデータ操作
  • データの取り扱いについては製品を提供する側として特に重要なところ
  • 製品提供の前提条件として正常なデータ操作ができるというのもある
  • 特にお金にかかわる部分でデータの矛盾が生じるとまずいよね…
  • トランザクションは、データを取り扱う上で無くてはならない仕組み
  • UPDATEやDELETE文の動作確認でもトランザクションをよく使う
  • 普段はテスト用のDBにテストのためにアクセスするだけなこともあって、DBは大勢が同時にアクセスするものだという前提を普段はあまり意識しない
    • お客様のデータを預かるためのものという意識をしっかり持ちたい
  • トランザクションは重要とわかりつつも、これまで本格的に学習したことが無かった気がする…
    • とにかく重要なので、今後も学習したい
コミットとロールバック
  • テスト用にデータを編集する際には、冒頭にBEGIN TRAN してから編集し、意図した結果になっているか・意図した以外の範囲を変更してしまってないかを確認したらコミットしている
  • ローカル以外の環境ではUPDATEなどでDBを更新する場合には必ず書くようにしている
    • 更新された件数を確認しコミットする
  • 複数テーブルにまたがる処理をする際にはよくトランザクションをきる
  • SQL文の作成はデータ抽出の作業ぐらいで直接触る機会はあまりないため、SQL文にトランザクションの指定をしたことはない
  • RailsだとRails側でデータの操作を行うため、トランザクションを掛ける際は専用のメソッドがあるのでそれを使っている
  • アプリのログを見ていると登録・更新処理でトランザクションが掛かっていることがわかる
  • 自動コミットモード→そもそも指定していなくてもトランザクションとして扱われている(トランザクションは指定したときだけだと思っていた)
  • 多くのツールは「自動コミットモード」で動作するというのは、普段あまり意識していなかったためなるほどと思った
  • SQL Server だと BEGIN だけじゃダメで、BEGIN TRANSACTION か BEGIN TRAN と書く必要があった気がする。COMMIT と ROLLBACK はふつうに書ける。
  • 普段は「BEGIN TRAN」「COMMIT TRAN」と書くようにしている
  • 不可分なものとして扱われる性質のことを原子性という(原子はこれ以上分割できないから、なるほど)
    • 余談ではあるがアトミックデザインだったり原子から命名されるものがほかにもある
トランザクションの分離
  • 分離レベルを指定してトランザクションをかけたことはない
  • トランザクションの分離レベルは設定したことがなく、普段意識していない。これを機に意識していきたい
  • 分離レベルまで意識してSQLを書けると良さそう
  • 複数人で同時アクセスした際に起こる問題について、3つに整理して説明されていてわかりやすかった
  • DBMSシステムの違いは使える関数や用語の違いがまず目につくが、分離レベル(READ UNCOMMITTEDがDBMSによっては無効である話)のコラムを読むと、思った以上に根本的な考え方のようなものが違うんだなと思った
  • PostgreSQLはデフォルトだとREAD COMMITTED
  • 副作用の種類はなんとなく聞いたことがあったけど、しっかり学べてよかった
    • ダーティリード: 別のトランザクションでコミットされていないデータが読み取れてしまう
    • 反復不能読み取り: 別のトランザクションで更新された後のデータを読み取ってしまう(こいつだけ名前が微妙だな… → ファジーリードとも呼ばれるそう、絶対そっちの方がかっこええ)
    • ファントムリード: 別のトランザクションで挿入されたデータが見えてしまう
  • トランザクション分離レベルは普段あまり意識したことがなかったので、今後は気を付けていきたい
    • READ UNCOMITTED (コミットされていないものを参照する → ダーティリードが起こりうる)
    • READ COMMITTED (コミットされたものを参照する → ファジーリードは起こりうる)
    • REPEATABLE READ (反復可能な参照 → ファントムリードは起こりうる)
    • SERIALIZABLE (逐次化 → トランザクションは必ずひとつずつ順番に実行される → 副作用が起こりえない)
ロックの活用
  • 排他ロックを表ごとにかけてしまうと影響範囲が大きいため、必要な行だけにするなどの注意が必要
  • ロックの範囲と強さは最低限にすることが大事
  • 幸い今まで製品でトラブルの原因になったことはないが、デッドロックが起きそうな場所は意識していきたい
  • デッドロックとかの話は資格試験で勉強したが、自動的にデッドロックを解決する仕組みがあることは知らなかった
  • 明示的にロックというのは使ったことがない。お客様のデータに入るようなときは使うのかな?
  • 複数対象にロックをかける際には同じ順番でロックをかけることでデッドロックを回避できる
  • SQL Serverでは SELECT * FROM table WITH (UPDLOCK, ROWLOCK) WHERE ~ のように WITH を使った書き方になる(行ロックもテーブルロックも)
  • つい最近ストアド実行時にテーブルをロックするクエリを書いた(というか既存の処理をコピーした)
    • 「SELECT~FROM~WITH (TABLOCKX)」
  • 実際にロックを使用する際には時間によるタイムアウトだったりを組み合わせる必要がありそう

まとめ

今回はトランザクションに関する章でした。安全な運用のためには必須の知識であることに加えて、これまで分離レベルなどは意識していなかったため今後は意識していきたいです。また、個人的には知らない間に自動コミットモードが作用していた部分が印象に残りました。 次回は第10章「テーブルの作成」になります。