(第3回)オンプレミスRDBでのビッグデータの蓄積【インデックス編】

(第3回)オンプレミスRDBでのビッグデータの蓄積【インデックス編】

目次

前回のおさらい
ビッグデータ蓄積・利用時の課題
課題に対応する方法
インデックスとは
チューニング
おわりに

前回のおさらい

前回は、以下のような前提条件からデータ量(ヒープデータ量)を見積りました。

  • 全国に10箇所の生産ライン工場を持つ
  • 工場は24時間稼働
  • 長期的(10~20年)にデータを蓄積
  • 収集するセンサデータの生成頻度は1分とし、センサの数は3000個/1工場

上記の条件から、10年間蓄積時のヒープデータ量は9テラバイト程度となることが推定されました。

今回は9テラバイトのデータ量を蓄積した場合に、想定される課題から、課題に対する対応策を考えていきたいと思います。

ビッグデータ蓄積・利用時の課題

多量のデータを取扱う場合に、以下のような問題点が懸念されます。

  • データ蓄積時(INSERT時)、1分以内(収集間隔内)で処理が完了されない。
  • データ利用時(SELECT時)に、データ量が多くレスポンスが悪くなる。

ビッグデータの蓄積・利用は「貯める・取り出す」の単純なフローとなるのですが、データ量が多くなると蓄積時間や参照時間への影響が大きくなり、許容可能な時間設定とのバランスが求められます。

データ蓄積時には、複数の拠点から1分間隔でデータが送信され、データベースに挿入(INSERT)されます。
このとき、INSERT処理に1分以上費やすと、次から次へと処理の負債が蓄積し、オーバーフローが発生してしまいます。

データ利用時には、指定された条件(工場、期間、センサなど)で出来るだけレスポンス良く、データを参照できることが要求されます。
ビッグデータ関連では、「いろんな側面からデータ分析をしたいから、指定した条件でパッとデータを取得・可視化させたい」ということが要求されることが多いため、せっかく蓄積したデータでも参照するのに数時間以上必要となるとビッグデータの利用価値は下がってしまいます。

課題に対応する方法

データ蓄積時の課題に関しては、INSERT処理だけなのでサーバのスペック(CPUやストレージのI/O)等に依ると思われるが、特に何も対応しなくても、収集間隔時間内に処理を完了することも考えられる。

しかし、1分間に10箇所×3000センサ=30000レコードがINSERTされることや、複数個所から同時にINSERT処理が行われるため、以下のような対応を検討してもよいのではないか。

  • インデックスを不用意に増やさない
  • 工場ごと程度にテーブルを分割する
  • DBファイルへのI/O分散のため、パーティション分割する

インデックスを増やしてしまうと、INSERT処理時にインデックスの更新処理が増加するため、処理が遅くなります。 (UPDATE時やDELETE時でもインデックス更新処理が行われるが、ビッグデータでは基本的にはINSERTのみの処理となる)

工場ごとにテーブルを分割したり、パーティション分割をすることによってデータベースやファイルへのI/O処理を分散させ、処理速度の向上や並行処理を狙えると考えます。

データ利用時の課題に関しては、一般的なSELECT性能の向上(チューニング)と同じような対応となるが、以下のような対応を検討することが必要だと考えられます。

  • 適切なインデックスを作成し、効率的な参照を行う
  • パーティション分割を実施し、データ参照範囲を減らす
  • データ圧縮を実施し、データのSeek性能を向上させる

データ量が多くなるとインデックスの影響は非常に大きくなります。実際に利用する際のSELECT文を考慮して効率的なインデックスを作成することが重要となります。

上記のインデックスを増やさない対応と相反する部分になりますが、INSERT処理とSELECT処理とのバランスを見ることも必要になってきます。

また、データ量が多いためデータの参照範囲や参照データ量を少なくすることで、SELECT処理を向上させることが考えられます。

以上のことから、

  • インデックスチューニング
  • パーティション分割
  • データ圧縮

を実施することで、ビッグデータを取り扱う課題の解決に有効と考えられます。

ここで、対応する案を列挙したが、細かな内容については、今回を含めて今後2~3回程度で記述していこうと思います。

インデックスとは

今回は上記の対応方法のうち、インデックスのチューニングについて記述していきます。

そもそもインデックスって何?あると何がいいの?どんな処理をしているの?と、データベースを使用している人でも意外に知らなかったりもします。

データベースを使用しているとよく出てくる単語なのに、なんとなくわかるが実はよく知らない。当たり前のように話されるとなかなか聞き辛かったりもして、そのままなんとなく使っている。というのはよくあることのように思います。

何を隠そう私もその一人だったときがありました。少しのデータをやりとりするだけのアプリケーションなどでは、インデックス(ユニークインデックスなどの一意を目的とするインデックスではなく、検索処理向上を目的としたインデックス)の必要性をあまり感じなかったりするからだと思いますが、データ量が多くなってくるとインデックスの影響力は大きくなり、考慮しないことはあり得ません。

インデックスについては、インターネットで調べるとたくさん情報は出てきますが、ここでも少しだけ記述したいと思います。

インデックスは、名前のとおりデータの索引のようなものとなり、テーブルや行の中からデータを参照の高速化を実現します。



では、インデックスはどのようにデータ検索の高速化しているのでしょうか。
前回の記事でも出てきましたヒープという実データがあり、ページ単位で格納されています。

非クラスター化インデックスも実データと同様にページ内に格納されていますが、データのキーとなる値とヒープデータの格納されているデータファイル番号・ページID・ページ内の行番で構成された行識別子(RID)が記録されています。

また、このキーとなる値からRIDを検索する場合に、B+Treeと呼ばれるアルゴリズムを利用し、高速化を実現しています。

全件検索ではO(n)と計算量が多いですが、BTreeではO(log[2]n)と計算量が少なくなり、B+TreeではBTreeよりもさらに計算量が小さくなります。(O(x)は参照するためにx回の検索が必要になることを表します。)
※[ ]は底数を表します。

他のRDBでも、インデックスは基本的にBTreeまたはB+Treeアルゴリズムを利用して高速化を図っています。

チューニング

今回の場合、プライマリキーに指定した条件のインデックスでも、参照SQLにキー条件をすべて記述することで、インデックスの効力が発揮されます。

SELECT * FROM DataTable
WHERE sample_id = '01'
AND sample_date BETWEEN '2018-12-01 00:00' AND '2018-12-31 23:59'
AND sample_name = 'Sensor_0001'
ORDER BY sample_date ASC

しかし、アプリケーションで使用するクエリ等でWHERE条件がすべて決まらない、正規表現で検索するなどの場合には、上記のインデックスは使用されないため、テーブルの全レコードから検索されることになります。その場合には適正な非クラスター化インデックスを付与したり、テーブル構造を見直すこともあります。

SQLServerには優秀なクエリオプティマイザーが搭載されており、最適なインデックスが使用されたり、不足しているインデックスがあれば表示してくれることもあります。

おわりに

今回は、多量なデータを扱う際の課題と対応案と、対応案の内インデックスについて記述してみました。

実際に業務で扱う場合には、利用方法や顧客の要求を満たす場合にはデータに他の情報を結び付けたり、データの集計・演算などをさせてみたりと、さらにレスポンスを考慮していかなければならない局面にたびたび遭遇するかと思います。次回はデータパーティショニングにて、ディスクI/Oの分散やSeek範囲の狭小でのレスポンス改善について記述予定です。