技術関連の覚書

案件でやったり自宅で試したことの覚書

SQLのパフォーマンスを最適化するために

ひとまず棚卸が終わったので、今回からちゃんと書いていきます。

これまで書いてあった物を見てDBのメモはあったけどSQLについて書いて無かったので今回はSQLについて書いていきます(ちょうど今やってることだし)。

SQLと言うのはいろいろな現場に行くごとに用語が違っていたりしてどれが標準的な言葉かわからない事もあるので、 まず言葉の定義からしておきます。

用語 意味 他の言い方
副問合せ SQLのFROM句やWHERE句で別のSQLを定義すること
副問合せの検索結果をWHERE条件にしたり、テーブルと同様に扱うことができる
サブクエリー
別名 テーブルや項目に対してつける別の名前
関数を使った場合にもつけることができ、選択式、テーブル名につけることができる
エイリアス
外表 テーブル結合時に基準になる側のテーブル
下記のSQLのTABLE1に該当するが、結合結果も次に結合がある場合はそれが外表として扱われるためTABLE1とTABLE2の結合結果もTABLE3に対する外表となる
外部表、駆動表
内表 テーブル結合時に外表から結合される側のテーブル
下のSQLではTABLE1に対するTABLE2、TABLE1とTABLE2の結合表に対するTABLE3
アクセスパス SQL実行時にどのような手順で実行していくかを示したもの 実行計画
SELECT
  COUNT(ITEM1) CNT, ITEM1 I1, ITEM2 I2
FROM
  TABLE1 T1
INNER JOIN TABLE2 T2 ON
  T1.ITEM1 = T2.ITEM1
INNER JOIN TABLE3 T3 ON
  T2.ITEM3 = T3.ITEM3
WHERE
  T1.ITEM2 = ? AND
  T2.ITEM1 IN (
    SELECT
      ITEM1
    FROM
      TABLE1
   ) SUB_T1
ORDER BY
  ITEM1
GROUP BY
  ITEM1, ITEM2
;

インデックスの使用

SQLのパフォーマンスをあげるための一つとしてインデックスを使用する方法があります。 インデックスとは、本の索引と同じく、頭文字などを見出しにしてそれがどこにあるかを記述しているところです。

f:id:boctok-ctpoba:20170331235955p:plain

インデックスを使うと、検索する量を減らせるため速度をあげることができます。

テーブルの結合順

テーブルの結合順や結合項目によってパフォーマンスが変わります。 結合の方法としては以下の物があります

  • NESTED LOOPS JOIN

  • SORT MERGE JOIN

  • HASH JOIN

  • CROSS JOIN

NESTED LOOPS JOIN

外表からインデックスを利用して内表を検索する結合方法なので、結合条件にインデックスが使われていることが必要 外表の件数を少なくすることで検索回数を減らすことができるので、件数の少ないテーブル、検索条件によって件数が絞り込まれるテーブルを外表にする

計算量:O(N \log{M}) *1

SORT MERGE JOIN

外表、内表をソートして上から順に検索して結合していく方法 外表が大量データの場合はNESTED MERGE JOINよりも有利な場合がある

計算量:O(N+M)

HASH JOIN

データベースで、2つの表の小さい方を使用して、メモリー内にハッシュ表を作成する結合 大きい方の表をスキャンしてハッシュ表を調べ、小さい方の表の対応する行のアドレスを見つけます メモリー内にハッシュ表を作るため大量のメモリが必要になるが、メモリが多い場合は有利な検索方法

計算量:O(N h_c + M h_m + J) *2

CROSS JOIN

外表から1レコードずつ内表を全件検索する方法 外表件数×内表件数だけの検索回数があるためパフォーマンスはもっとも悪い

計算量:O(NM)

計算量についてはここを参照しました www.madeiradata.com

今日はここまで 意外に時間がかかりました(数式の書き方調べたり色々と)

さーて、明日のこのブログは

インデックスを使えなくする検索条件

インデックスを使う優先順位

副問合せの検索方法

の3本です 来週もまた見てくださいね

と言いながら、明日は出かけるのでかけるかどうかわかりません

(某国民的アニメとは関係ありません)

*1:Oは計算量を表す記号、括弧内に入る数に応じて変化する量。N,Mは外表、内表のそれぞれの件数

*2:件数はN<M、hc:ハッシュテーブルを作る計算量、hm:ハッシュマッチングの計算量、J:Jorker=ハッシュ関数の動的な計算量

Linuxでのファイル復旧

このツールを使います DiskDiggerdiskdigger.org

なぜか拡張子がexe

$ sudo apt-get install libmono-system-windows-forms4*

Download DiskDigger, unzip it, and launch it with sudo:

$ wget http://diskdigger.org/diskdigger_linux.zip
$ unzip diskdigger_linux.zip
$ sudo mono DiskDigger.exe

If the above line gives an error, try explicitly specifying the runtime version:

$ sudo mono --runtime=v4.0 DiskDigger.exe

Elasticsearch

※この情報は古いのであまりあてになりません。現時点の最新版は5.3.0です。

インストール前提

jdk1.7以上をインストール済みであること rootユーザで実行する

インストール

yumを使ってインストールするためにアクセスキーをインポートする

rpm --import https://packages.elastic.co/GPG-KEY-elasticsearch

/etc/yum.repos.d/elasticasearch.repo を作成する

[elasticsearch-2.x]
name=Elasticsearch repository for 2.x packages
baseurl=https://packages.elastic.co/elasticsearch/2.x/centos
gpgcheck=1
gpgkey=https://packages.elastic.co/GPG-KEY-elasticsearch
enabled=1

yumでインストール

yum -y install elasticsearch

サービスを登録

systemctl daemon-reload
systemctl enable elasticseach
systemctl start elasticsearch

起動確認 サーバ上で

# curl http://localhost:9200
{
  "name" : "Him",
  "cluster_name" : "elasticsearch",
  "version" : {
    "number" : "2.3.3",
    "build_hash" : "218bdf10790eef486ff2c41a3df5cfa32dadcfde",
    "build_timestamp" : "2016-05-17T15:40:04Z",
    "build_snapshot" : false,
    "lucene_version" : "5.5.0" 
  },
  "tagline" : "You Know, for Search" 
}

プラグインの導入

プラグインを導入するためのコマンドは Elasticsearchインストールディレクトリ /bin/plugin パスを通すかフルパス指定で実行してインストール plugin install インストールプラグイン名 入れておきたいプラグイン

プラグイン インストール文字列 用途
Marvel Documentation elasticsearch/marvel/latest 管理、モニタ用
Kuromoji /elasticsearch/elasticsearch-analysis-kuromoji/2.0.0 日本語解析
CSV River Plugin river-csv -url https://github.com/AgileWorksOrg/elasticsearch-river-csv/releases/download/2.0.1/elasticsearch-river-csv-2.0.1.zip CSVデータインポート

Couchbase

インストール

公式サイト からインストールファイルをダウンロードする。

インストーラを実行するとそのままサーバの起動までスタートします。

http://インストールサーバ:8091 へアクセスすると設定画面が開きます。

Apache Solr

概要

インストール

  1. apache solrのページからダウンロード

  2. ダウンロードファイルを解凍する

  3. 解凍したディレクトリへ移りbin/solr -p ポート番号 で起動する

$ wget http://ftp.tsukuba.wide.ad.jp/software/apache//lucene/solr/5.3.0/solr-5.5.0.tgz
$ tar -zxvf solr-5.5.0.tgz
$ cd solr-5.5.0
$ bin/solr -p 接続ポート

PostgreSQL

インストール

yum -y install postgresql postgresql-server

postgresql-setup initdb

/var/lib/pgsql/data/postgresql.confの編集

#listen_addresses = 'localhost'         # what IP address(es) to listen         on; <=ローカルホストのみ、コメントアウト
listen_addresses = '*'          # what IP address(es) to listen on; <= コメントアウトを外して、全ホストからのアクセスを許可
[root@zeke ~]# systemctl start postgresql
[root@zeke ~]# systemctl enable postgresql
Created symlink from /etc/systemd/system/multi-user.target.wants/postgresql.service to /usr/lib/systemd/system/postgresql.service.

[root@zeke ~]# firewall-cmd --add-service=postgresql --permanent
success
[root@zeke ~]# firewall-cmd --reload
success

[root@zeke ~]# firewall-cmd --add-service=postgresql --permanent
success
[root@zeke ~]# firewall-cmd --reload
success

初期設定

デフォルトユーザ(postgres)のパスワード変更

[root@zeke ~]# su - postgres
-bash-4.2$ psql -c "alter user postgres with password 'password'" 
ALTER ROLE

ユーザとDBの作成

-bash-4.2$ createuser user
-bash-4.2$ createdb dbname -O user

MyBatis

ファイル構成

種類 クラス名パターン 役割 ジェネレータで生成するもの 注意点
エンティティ テーブル名のキャメルケース テーブル項目の内容を保持するためのbean テーブル項目名に該当するフィールド、getter、setter キー項目はKeyクラスに実装
キー エンティティ+Key テーブルのキー項目の内容を保持するためのbean キー項目に該当するフィールド、getter、setter エンティティの親クラス
Example エンティティ+Example エンティティに対する条件などを保持する 条件式の実装はサブクラスのCriteriaに設定する
Mapper エンティティ+Mapper SQL文とマッピングするためのインタフェース update,insert,selectByExample,selectByPrimaryKey

エンティティの結合

結合エンティティ

全項目列挙→契約エンティティ、契約異動履歴エンティティクラスのフィールドとgetter,setterに変更

結合エンティティMapper.xml

SQLのSELECTをエイリアス.項目名 エイリアス_項目名 で列挙して、すべての項目に別名を作成 resultMapタグ内を以下のように設定 共通IDフィールドは各テーブルに持つ共通の項目となるもの エンティティのresultMapは外部参照ができるので 1対多の場合はcollectionタグを使う collectionにはofTypeにリスト要素の型を指定する

<mapper namespace="jp.example.exex.data.mapper.BindMapper" >
  <resultMap id="結合ResultMap" type="パッケージ.結合エンティティ" >
    <id property="共通IDフィールド1" column="共通IDカラム1"/>
    <association property="t1" columnPrefix="t1_" javaType="パッケージ.エンティティ1" resultMap="マッパー名1.リザルトマップ名"/>
    <association property="t2" columnPrefix="t2_" javaType="パッケージ.エンティティ2" resultMap="マッパー名2.リザルトマップ名"/>
    <collection property="t3" ofType="エンティティ3" columnPrefix="t3_" javaType="パッケージ.エンティティ3" resultMap="マッパー名3.リザルトマップ名"/>
  </resultMap>
  <sql id="t1Columns">
    t1.共通IDカラム 共通IDカラム,
    t1.IDカラム1 t1_IDカラム1, t1.IDカラム2 t1_IDカラム2, t1.IDフィールド t1_フィールド, ...
  </sql>
  <sql id="t2Columns">
    t2.IDカラム1 t2_IDカラム1, t2.IDカラム2 t2_IDカラム2, t2.IDカラム3 t2_IDカラム3, t2.IDフィールド t2_フィールド, ...
  </sql>
  <sql id="t3Columns">
    t3.IDカラム1 t3_IDカラム1, t3.IDカラム2 t3_IDカラム2, t3.IDカラム3 t3_IDカラム3, t3.IDフィールド t3_フィールド, ...
  </sql>
  <select id="selectマッパーメソッド名" resultMap="結合ResultMap">
    SELECT
      <include refid="t1Columns"/>,
      <include refid="t2Columns"/>
    FROM
      テーブル1 t1,テーブル2 t2
      ...
  </select>
   :

エンティティクラスの実装

public class BindEntity {
    /** 共通のIDカラムの型 */
    private DataType id;
    /** T1テーブルエンティティオブジェクト */
    private T1 t1;
    /** T2テーブルエンティティオブジェクト */
    private T2 t2;
    /** T3エンティティのリスト */
    private List<T3> t3List;

    // それぞれのgetter,setter
}

resultMapは結合エンティティのリストへ設定 テーブル内容のマッピングはassociationのプロパティで設定したフィールド名とjavaTypeで指定した型でcolumnPrefixで指定したプレフィックスを持つ項目をエンティティオブジェクトへ挿入する