宮水の日記

宮水の日記

主に書評や資格取得について記事を書いています。

「SQL実践入門」を読みました

今月はSQL強化月間ということにして、「SQL実践入門」を読みました。

なぜ読んだのか

  • 普段Active Recordばかり使っていて、SQLに向き合ったことがなかったから。
  • 文法だけじゃなくてSQLの仕組みについてちょっと知りたいと思ったから。

この本で学べること

  • パフォーマンスの良いSQLの書き方、特に大量データを処理するSQLの性能向上の方法
  • データベース内部のアーキテクチャやストレージのようなハードウェアの特性まで含めた総合的な知識

本の概要

第1章:DBMSアーキテクチャ──この世にただ飯はあるか

第1章では、RDBの内部的な動作に関するモデルを理解し、SQLのパフォーマンスに関係する「バッファ」「オプティマイザ」などの概念を理解します。データベースは、その仕組みから「容量・永続性・データの整合性」と「速度」がトレードオフの関係になっていたり、SQLを実行可能な手続きに変換するために実行計画を作っていることがわかりました。

1章で出てきた単語

クエリ評価エンジンユーザーから受け取ったSQLを解釈し、どのような手順で記憶装置のデータへアクセスに行くか決定する。

バッファマネージャメモリ領域の使い方を管理する。ユーザとストレージとの間に割って入り、SQL文のディスクアクセスを減らす役割がある。

ディスク容量マネージャどこにどのようなデータを保存するかを管理し、それに対する読み出し/書き込みを制御する。

トランザクションマネージャとロックマネージャトランザクション同士をうまくデータの整合性を保ちながら実行させたり、データにロックをかけて待機する。

リカバリマネージャ定期的にバックアップを取得し、いざという時にデータを復旧する。

キャッシュユーザーとストレージの中間に位置することでデータの転送遅延を緩和するための機構

オプティマイザインデックスの有無、データの分散や偏りの度合い、DBMSの内部パラメータなどの条件を考慮して、選択可能な多くの実行計画を作成し、それらのコストを計算して、最も低コストな1つに絞り込みます。

LRU(LeastRecentlyUsed) 「参照される頻度が最も少ないものをキャッシュから追い出す」というアルゴリズム。逆に頻繁に参照されるデータが長くキャッシュに留められるため、全体としてのキャッシュヒット率が上昇する。

第2章:SQLの基礎──母国語を話すがごとく

この章では、SQLの基本構文を理解します。

基本の構文については、

  • SELECT句
  • WHERE句 / 複数のOR条件をまとめて書けるINを使った記述
  • GROUP BY句
  • 集計用の関数(COUNT、SUM、AVG、MAX、MIN)
  • HAVING句
  • ORDER BY句

そして、SELECT文をデータベースに保存できるビューという機能や、サブクエリについて解説されていました。

応用として、

  • CASE式
  • UNION(和集合)
  • INTERSECT(積集合)
  • EXCEPT(差集合)
  • ウィンドウ関数

について。

そして最後に INSERT、DELETE、UPDATE構文について解説されていました。意外とSQLの構文って少ないのですね。

第3章:SQLにおける条件分岐──文から式へ

この章では、CASE式がパフォーマンス改善で重要であることを学びます。CASE式で条件分岐を表現できればテーブルへのスキャンを大幅に減らすことができるケース、UNIONで愚直に書いた方がパフォーマンスがいいケースなど、実行計画を読み解くことで明らかにしていきます。

"文"ではなく"式ベース"でクエリを考える大切さを学びました✨

第4章:集約とカット──集合の世界

SQLの特徴的な考え方に、集合指向といって、行の「集合」単位でひとまとめにして記述するというものがあります。集約関数には、COUNT, SUM, AVG, MAX, MINなどがあります。これらは複数行を1行に集約する機能を持っている関数です。カットとは、母集合である元のテーブルを小さな部分集合に切り分けることを言います。この章では、集約関数とカットの効果的な使い方について学びます。手続き型言語だとループや分岐を使って記述しないといけない複雑な処理を、SQLの集約関数を使えばスッキリ簡単に書けるケースがあることがわかりました。

第5章:ループ──手続き型の呪縛

SQLの世界には、ループがありません。SQLの世界に手続き型言語のようにループを持ち込んで処理を書くとパフォーマンスが悪くなってしまうケースがあります。
SQLの世界でループを使うことのデメリットや、その代替となる手段を学びます。

第6章:結合──結合を制する者はSQLを制す

結合のアルゴリズムは大きく分けてNested Loops, Hash, Sort Mergeの3つがあります。この章では、この3つの結合アルゴリズムの実行計画を読み解き、RDBがどのように結合を最適化しているか学びます。ちなみに、この章を読んで初めてなぜ内部結合と外部結合が、なぜ「内部」と「外部」と呼ばれるのかわかりました。

第7章:サブクエリ──困難は分割するべきか

サブクエリとは、SQLの中で生成される一時的なテーブルです。サブクエリとテーブルは機能的観点から見ると違いはありませんが、パフォーマンスの観点から見ると大きな違いが存在します。

サブクエリの問題点は以下です。

  • 実体的なデータを保持していないので、アクセスするたびにデータを作る必要があり、実行コストがかかる。
  • 計算結果を保持するためにI/Oコストがかかる
  • 制約やインデックスのようなメタ情報が存在しないため、最適化を受けられない。

この章では、サブクエリの問題点を解決する方法とサブクエリを使ったほうがパフォーマンスがいいケースを見ていきます。

第8章:SQLにおける順序──甦る手続き型

SQLは昔、順序を持った数を扱うための機能を持っていませんでした。ところが、実務においては適当な集合に対して連番を求められるケースが多くあります。そうした実務的な要望に応えるために、SQLにも順序と連番を扱うための機能が追加されました。

この章では、ウィンドウ関数や相関サブクエリを利用して行に対して連番を振る方法や、それを応用して中央値を求めたりします。

第9章:更新とデータモデル──盲目のスーパーソルジャー

SQL文を変えることよりも、データモデルを変更したほうがパフォーマンスがよくなるケースをみていきます。

第10章:インデックスを使いこなす──秀才の弱点

インデックスの利用方法について学びます。インデックスのアルゴリズムを知り、それを有効活用する方法、どのような条件下で性能向上が難しいかなどを取り上げています。

感想

当たり前ですが、SQLに関してかなり踏み入った話もあったので、難易度は高めの本でした。
それでも今までなんとなく文法だけ覚えて使っていたSQLでしたが、この本を読んで、データベース内部のアーキテクチャや、集合指向の概念、SQLで使われているアルゴリズムなどを知ることができました。SQLの中身を知ることで、アプリケーション側でもデータをどのように扱うのか意識できるので、より良い設計を勉強できるきっかけになったと思います。読んで良かったです。次はデータモデル設計の本を読んでみようと思います。

ここまでお読みいただきありがとうございました!