ぱと隊長日誌

ブログ運用もエンジニアとしての生き方も模索中

「SQLパフォーマンス詳解」(原文タイトル:SQL Performance Explained)の紹介と購入時のポイント

本の紹介

SQLパフォーマンス詳解」(原文タイトル:SQL Performance Explained)はデータベースのBツリーインデックスについて解説しています。インデックスの仕組みから実務に活かせるテクニックまで幅広く取り上げられています。
データベースのインデックスは本やセミナー資料で度々取り上げられる内容ですが、この本はそれらの内容を1冊にまとめ上げています。どこかで見たのだけど…と探して回る前に、この本を紐解けばすぐにみつかるかもしれません。

本はOracleを中心とした構成ですが、補足でMySQLPostgreSQLSQL Serverについても解説しています。著者によれば、Bツリーインデックスは多くのデータベースでほぼ同じように動作すると述べていますし、どのデータベースでも通用する内容となっています。

実はこの本のほぼ全文がオンラインで公開されています。
Use The Index, Luke
データベースのインデックスやパフォーマンスチューニングについて調べているうちに、このサイトへたどり着いた方も多いのではないでしょうか。私もPostgreSQLのインデックスについて調べているうちにたどり着きました。

Webにて無償で公開されているものを購入するのはもったいなく感じるかもしれません。私の場合は著者(@さん)及び翻訳者(@さん)へ恩返ししたいという気持ちからPDF版を購入しました。また、Web版よりPDF版のほうがよみやすく感じました。

まずはオンライン版で内容を確認し、興味を持たれたら購入を検討されてはいかがでしょうか。

日本語版の購入方法

購入サイトはこちらになります。
SQLパフォーマンス詳解
念のためVirusTotalでスキャンしましたが、Clean Siteとの判定でした(2017/03/05時点)。

印刷版とPDF版があります。
印刷版は海外のAmazon(.com/.co.uk/.de)で購入できます。上記サイトから遷移できます。なお、現時点で日本のAmazonからは購入できません。
PDF版は上記サイトから購入できます。2017/03/05時点で9.95ユーロ(約1,300円)でした。

上記サイトからの購入の場合、価格表示はユーロです。支払いはPayPalを利用しています。

PDF版購入の場合、プルダウンでPDFを選択し、「レジへ」ボタンをクリックするとPayPalへ遷移します。PayPalで支払いを済ませると、PayPal登録のメールアドレスへPDF版ダウンロードリンクを含んだメールが届きます。

割引コードの適用

利用可能(2017/03/05時点)な割引コードがありました。PDF版であれば9.95ユーロが5.00ユーロへディスカウントされます。

@さんのブログにコードが記載されています(ここではコードを転記しません)。
SQLのインデックスについて解説した洋書が良かった件。PDF版もあるよ(2012/10/22までの割引購入クーポン有) - Dマイナー志向
ただ、上記エントリによれば本来は2012/10/22で期限が切れるはずだったので、著者が寛大なのか、それとも無効化を忘れているだけかもしれません。
このような背景があるため、購入時点で割引率が変わっていたり、無効になっていたとしてもご了承ください。

割引コードの入力方法を説明します。
「レジへ」ボタンの下にある「割引コードを入力」リンクをクリックします。
割引コードを入力し、「買い戻す」ボタンをクリックします。
すると、表示された価格が当初よりディスカウントされているはずです。コードが無効な場合はエラーとなります。

f:id:pato_taityo:20170305164327p:plain

PayPal支払いでの為替レートと手数料

海外サイトでの購入で気になることの一つに為替レートと手数料があります。
PayPalでは為替レート及び手数料をPayPalとクレジットカード会社から選べます(一部のカードブランドでは選べないようです)。詳細については以下の記事を参照ください。
PayPalの高い日本円の為替手数料(レート)を安く節約する方法

まとめ

SQLのパフォーマンスを上げるためにはインデックスを理解することが重要となります。インデックスにはいくつか種類がありますが、中でもBツリーインデックスは基本といえます。この本(およびサイト)はその基礎知識を学ぶ上でお勧めできます。
今回の本をお勧めするにあたり、本の内容は公開されているため、不安を抱きやすい購入手順を中心にまとめました。ご興味を持たれた方の参考になれば幸いです。

PDCA(Plan, Do, Check, Action)サイクルのActionとは何か?

疑問

PDCA(Plan, Do, Check, Action)サイクルについて、これまで何度も講義やセミナーで説明を受けてきましたが、どうしてもDo(実行)とAction(改善)の違いを理解できませんでした。
また、PDCAは「サイクル」であり、P→D→C→A→P→…のように繰り返すと説明されます。この「改善」の行動をした後に「計画」するということに違和感がありました。

解決

そんな悩みに対し、こう考えてはどうかとアドバイスがありました。
P : 計画
D : 実行
C : 評価(計画と実績の差異確認)
A : 改善(差異に対して行うアクションの決定)

改善(A)フェーズで計画と実績の差異の是正のために行うアクション(行動)を決定します。そして、決定したアクションを次の計画(P)フェーズで計画に組み込み、実行(D)フェーズで行動します。確かにこれであればA→Pへのつながりも自然なものとなります。

また、WEB+DB PRESS(プログラミング技術情報誌)の記事でPDCAの"A"は「Action(行動)」ではなく「Adjust(調整)」だと解説していた、というエントリもありました。
PDCAの「A」がActionじゃなくてAdjustって聞いてめっちゃしっくりきた話 - SUKEMATSU.NET
こちらのほうがしっくりくる方もいるかもしれません。

最後に

PDCAサイクルは行動することが最も大切です。そして、PDCAサイクルの定義について腹落ちしていれば、行動したときの納得感が変わってきます。今回のエントリがその一助となれば幸いです。

SQLのWHERE句で用いられる相関サブクエリを理解する

はじめに

相関サブクエリもしくはEXISTS述語の使い方として、以下のようなSQLがよく取り上げられます。

SELECT *
  FROM item i
 WHERE EXISTS
  (SELECT *
     FROM stock s
    WHERE i.id = s.id);

これに対して以下のデータが与えられたとします。

◆itemテーブル

id name
1 みかん
2 バナナ
3 リンゴ
4 ぶどう

◆stockテーブル

id quantity
1 10
3 30

この時、EXISTS述語内のサブクエリ"SELECT * FROM stock s WHERE i.id = s.id"だけを見て、以下のように考えてしまうことは無いでしょうか?
※補足:このサブクエリ単体では"i"を定義していないため、エラーとなります。実行するにはFROM句に"item i"の追加が必要です。以下同様です。

EXISTS述語内のサブクエリが2行返す
  ↓
EXISTS述語の評価がTRUEとなる
  ↓
WHERE句の評価がTRUEとなる
  ↓
WHERE句がTRUEのためitemテーブルの全行を返す

ですが、最終的な結果としては2行しか返ってきません。
どこで勘違いが起きてしまったのでしょうか?本エントリではこの疑問について説明します。

理解のポイントはWHERE句の処理にある

先日、WHERE句について解説するエントリをアップしました。
SQLのWHERE句の処理を理解する - ぱと隊長日誌
このエントリでSQLのWHERE句を「集合から条件に合致する行を選択する」処理であり、WHERE句の評価は1行ずつ行われる、と説明しました。
これを理解できればWHERE句の相関サブクエリを理解できます。冒頭の例について、処理の流れに沿いながら確認していきましょう。

(1)
FROM句でitemテーブルが指定されているため、対象となる集合は以下となります。

i.id i.name
1 みかん
2 バナナ
3 リンゴ
4 ぶどう

(2)
WHERE句は1行ずつ処理されるため、まずは先頭の行を評価します。

i.id i.name
1 みかん

(3)
ここでEXISTS述語内のサブクエリを実行します。

SELECT *
  FROM stock s
 WHERE i.id = s.id;

WHERE句が評価しているのは"i.id = 1"ですので、このクエリは以下のように動きます。

SELECT *
  FROM stock s
 WHERE 1 = s.id;

このクエリの結果を示します。

s.id s.quantity
1 10

(4)
サブクエリが1行返したため、EXISTS述語はTRUEとなります。
結果、WHERE句はTRUEとなり、WHERE句の評価していた行が選択されます。

i.id i.name
1 みかん

(5)
以降、対象となる集合の全ての行を処理するまで(3)から繰り返します。
結果として以下の行が選択されます。

i.id i.name
1 みかん
3 リンゴ

WHERE句が常にTRUEとなると勘違いをしてしまった方は、相関サブクエリがitemテーブルとstockテーブルの各集合に対して実行されると考えたのではないでしょうか。
処理を正しく理解するためには、WHERE句はitemテーブルの各行に対して評価されるため、itemテーブルのWHERE句で評価されている行とstockテーブルの集合に対してサブクエリが実行されると理解することが必要です。

単なる(相関でない)サブクエリであればどうなるのか?

このようなSQLであればどうでしょうか?

SELECT *
  FROM item i
 WHERE i.id = (SELECT max(s.id)
                 FROM stock s);

先ほどの例と同様にitemの各行毎にサブクエリが実行されると考えても構いませんが、サブクエリだけが先に実行されると考えても同じ結果となります。なぜなら、外側のクエリで使われているitemテーブルの列をサブクエリで参照していないからです。WHERE句がitemテーブルのどの行を評価していたとしても、サブクエリの結果は変わりません。

サブクエリを先に実行すると以下のSQLとなります。

SELECT *
  FROM item i
 WHERE i.id = 3;

結果は以下の通りです。

i.id i.name
3 リンゴ

まとめ

SQLを理解するためには処理の流れを理解することが大切です。
今回の例でいえば、WHERE句の処理を理解せずに()で囲まれた箇所を先に評価すると理解してしまうと失敗します。

この誤った理解でも以下のSQLは正しく評価できます。

SELECT *
  FROM item i
 WHERE i.id = (SELECT max(s.id)
                 FROM stock s);

でも、別のSQLは正しく評価できません。

SELECT *
  FROM item i
 WHERE EXISTS (SELECT *
                 FROM stock s
                WHERE i.id = s.id);

このエントリがSQLを理解するための一歩となれば幸いです。

参考資料

プログラマのためのSQL 第4版

プログラマのためのSQL 第4版

プログラマのためのSQL 第4版

SQLが途中どのように処理されて最終結果に至るかを細かく解説しています。この途中処理こそがSQLを理解するためのカギとなります。
かなりの分量ですので通読は難しくとも、SQLを書いていて気になったことを調べるときに必要な箇所を参照してみてはいかがでしょうか。

達人に学ぶSQL徹底指南書

達人に学ぶ SQL徹底指南書 (CodeZine BOOKS)

達人に学ぶ SQL徹底指南書 (CodeZine BOOKS)

EXISTS述語を述語論理の観点から解説しています。また、相関サブクエリの応用例についても説明されています。