応答時間、スループット、そして水平スケール


高価なハードウェアを使うようにしたからと言って、必ず処理が高速になるとは 限りません。しかし、通常はそれでたくさんの処理を行うことが可能になります。 高価なハードウェアは、高速な車と言うより、広い高速道路に例えるべきでしょう。 つまり、それ自体によってスピードを出すことはできないし、それが許されていない かもしれません。しかし、多くの車線はあるのです。これが、ハード ウェアに投資しても、必ずしも遅いSQLクエリを速くすることにつながらない 理由です。

今や90年代ではありません。その頃、CPUコア1つの計算性能は急速に向上 していました。多くの応答時間の問題は、新しいハードウェアを 導入することで解消されました。CPUが高速になったからです。それは さながら毎年旧モデルの2倍高速な新しいモデルの車が発売されるような ものでした。しかし、21世紀初めの数年間で、1CPUコアあたりの処理能力は 頭打ちになり、その点での改善はほとんど見られなくなりました。 より高性能なCPUを発売し続けるため、各ベンダはマルチコア戦略を取り 始めました。しかしそれは、複数のタスクを同時に処理することはできても、 1つしかタスクがない時のパフォーマンスを上げることはできません。つまり、 パフォーマンスを複数の側面から考える必要があるようになったのです。

水平方向のスケール(サーバの追加)にも、同じ制限があります。 より多くのサーバがあればよりたくさんのリクエストを処理できますが、 個々のクエリの応答時間は高速にはなりません。検索を高速にするには、 CouchDBMongoDBと いったリレーショナルでないシステムの場合も含め、効率的な検索ツリーが 必要になります。

重要

リレーショナルなSQLデータベースかリレーショナルでないシステムかに 関わらず、正しいインデックスを作ることは、クエリの応答時間を 短くする最善の方法です。

適切なインデックスを作るのはすなわち、Bツリーインデックス対数スケーラビリティの威力を 十分に引き出すことです。しかし残念なことに、インデックスの作成は 非常にずさんに行われることも多いのです。「データ量に対する応答時間」の図では、そういったずさんな インデックスを明らかにするものです。

図3.5 データ量に対する応答時間


ずさんなインデックスと正しいインデックスの応答時間の違いは 驚くほどはっきりしています。この違いを、ハードウェアを追加することで 埋め合わせるのは難しいでしょう。例えハードウェアによって応答時間を 小さくしようとしても、それが最善の方法なのかについては疑問が残ります。

いわゆるNoSQLシステムの多くは、あらゆるパフォーマンス問題は スケールアウトで解決できるとしています。ただし、ここで言う スケーラビリティは、多くの場合書き込み処理を対象にしていて、 結果整合性(eventual consistency) モデルに従ったものです。SQLデータベースは書き込み処理を遅くする 原因になる厳密な整合性モデルを採っていますが、それが必ずしも スループットが悪いことを示すわけではありません。これについての詳細は、 「結果整合性とCAP定理」と いう題のボックスを参照してください。

結果整合性とCAP定理

分散システムにおいて厳密な整合性を保とうとすると、ノード間での あらゆる書き込み処理を同期的に行う必要があります。この原理には、次の2つの 好ましくない副作用があります。(1) レイテンシと応答時間が 増加します。(2) 書き込みを完了させるために、同時に複数のメンバが有効な 状態でなければならないので、全体の可用性が低下します。

分散SQLデータベースは、共有ストレージを 使ったり、マスタスレーブレプリケーションを使用した計算機クラスタと 混同されることがあります。実際、分散データベースは ERPで 統合されたウェブショップによく似ています。そこでは、2つの商品が ある時は、それぞれが別のベンダから購入したものです。2つのベンダの システム間に整合性があるということは、2相 コミット(2PC)プロトコルを使った理想的なゴールです。 このプロトコルは、複数のデータベースに渡っていわゆる 「全部あり、あるいは全部なし(all-or-nothing)」な振る舞いをする グローバルトランザクションを実行します。グローバルトランザクションが 成功するには、関係する全てのメンバが有効な状態でなければなりません。 このため、全体の可用性が下がってしまうのです。

分散システムのノードが増えると、厳密な整合性を担保するのが 難しくなります。ノード数が数台を超えただけで、厳密な整合性を保つのは ほとんど無理になってしまいます。その一方で、整合性を犠牲にすることで、 可用性の問題を解決し、応答時間の増大を阻止できます。 このアイディアの基本は、ノードの一部に対する書き込み処理が終わった後で、 グローバルな整合性を回復するというものです。しかしこの方法には、ある 1つの問題が残されます。矛盾した変更が2台以上のノードで行われてしまう ことを防げないのです。矛盾を防ぐのではなく、 うまく扱うことで、結果的に 整合性が取れるのです。つまりこの考え方だと、整合性が 取れているというのは、全てのノードのデータが正しい、あるいは最適な データであることではなく、同じデータを持ってさえいればいいという ことになります。

BrewerのCAP 定理は、 一貫性(Consistency)、 可用性(Availability)、 分断耐性(Partition tolerance)の3つの間にある 依存についての一般性を述べたものです。

ハードウェアを増やしても、通常は応答時間は改善されません。 実際には、システムが複雑になることでレイテンシが蓄積するため、システムは 遅くなってしまう可能性すらあり得ます。アプリケーションとデータベースが 同じコンピュータ上で動作している場合、ネットワークのレイテンシは 問題になりませんが、本番環境ではデータベースとアプリケーションを それぞれ専用のハードウェアで動かすことが多いので、そういった構成は 一般的ではありません。セキュリティポリシー上、アプリケーションサーバと データベースの間にファイアウォールを置かなくてはならない時もありますが、 これもネットワークレイテンシを倍増させる原因になります。インフラが 複雑になればなるほど、レイテンシが積み重なり、応答時間は遅く なっていきます。こう言ったことが、高価な本番用ハードウェアが、安価な デスクトップPCの開発環境よりも遅いという、直感に反する振る舞いにつながる ことがあります。

このウェブサイトにぴったりのカップは僕たちのショップにあります。
#見た目もいい感じだし、ここでの僕の仕事を支えてくれています

もう1つ非常に重要なレイテンシに、ディスクのシークタイムがあります。 回転するハードディスク(HDD)は、要求したデータを読み込むために機械的な パーツを指定した場所に動かすのに、通常数ミリ秒という比較的長い時間を 要します。この時間は、4階層のBツリーを走査する時には4倍かかるわけですから、 合わせて数十ミリ秒かかることになります。それはコンピュータにとっては永遠に 思われる程の時間ですが、1度しか行われない処理なら、我々の認識できる 長さとまではいかないでしょう。しかし、1つのSQL文で数百、場合によっては 数千回のディスクシークが起きることも普通にあることで、特に複数の テーブルを結合する時にはなおさらです。キャッシュによってこういった問題は劇的に 改善されますし、SSDのような新技術によって、 シークタイムは桁違いに減りますが、それでもなお結合は遅い処理だと 言えるのではないでしょうか。次の章では、効率のよいテーブル結合のための インデックスの使い方を説明します。

SSD (Solid State Disk)キャッシュ

SSD (Solid State Disks)は、稼働部品のない大容量記憶装置です。 SSDの通常のシークタイムは、HDDのシークタイムと比べると桁違いに 高速です。SSDは、2010年ごろにはエンタープライズ向けのストレージとして 使われるようになりましたが、コストが高いことと寿命が短いため、 データベースではあまり一般的に使われていませんでした。

データベースは、アクセス頻度の高いデータを主記憶にキャッシュ します。これは、インデックスリーフノードのようにインデックスへの アクセスの度に必要なデータには特に便利な仕組みです。データベースは、 インデックスの走査の度にディスクシークが起きないように、よく使われる インデックスを完全にキャッシュします。

Factbox

  • パフォーマンスには、2つの側面があります。 応答時間と、スループットです。

  • ハードウェアを増やしても、クエリの 応答時間は通常は改善されません。

  • クエリの応答時間を改善する唯一の方法は、 適切なインデックスを作ることです。

Photo of Markus Winand
Markus Winand氏は、開発者がSQLパフォーマンスを改善するお手伝いをしています。 彼は、SQL Performance Explainedの 著者でもあり、出張トレーニングhttp://winand.at/での リモート講義も 行っています。