DBとAPIサーバのパフォーマンスチューニングの調査

## はじめに
- 業務で、**DBとAPIサーバ**のパフォーマンスチューニングを行う予定なのですが、全く行ったことがなかったので、どのような手順や方法で進めていくのか調べてみました。

## 目次
1. パフォーマンスチューニングとは
2. パフォーマンスチューニングの種類
3. SQLチューニング
4. indexチューニング
5. auroraについて
6. APIサーバ側のチューニングについて

## 1. パフォーマンスチューニングとは
パフォーマンスチューニングの説明として、一番しっくりきました。

> システムの**処理性能**や**信頼性**を高めるために，システムの動作環境を**最適化**することです。パフォーマンスチューニングを実施することで，システムの性能を最大限に生かし，安定稼働させられるようになります。
> 
>   [Cosminexus V9 アプリケーションサーバ システム構築・運用ガイド](http://itdoc.hitachi.co.jp/manuals/link/cosmi_v0970/03Y0260D/EY020046.HTM)

一般的には、``SQLやDBのチューニング``を指しているようでした。
パフォーマンスチューニング　≒　SQLやDBのチューニング

## 2. パフォーマンスチューニングの種類
今回は、**バックエンド側**のみです。主なパフォーマンスチューニングは、以下の通りでした。

- ``SQLチューニング``
- ``DBチューニング``
- ``APIサーバ側のチューニング``

具体的には、以下のようなチューニングを行うことが可能です。

#### SQLチューニング
```
- indexの追加・削除
- SQLを書き換える
- データ型の見直し
```
#### DBチューニング
```
- MySQLパフォーマンスチューニング -my.cnfの見直し
```

#### APIサーバ側のチューニング
```
- 不要なクエリ
- APIサーバとDBのロジックの比率の修正
```

## 3. SQLチューニング
**やればやるだけ**性能が良くなります。チューニングの手順は以下のようになります。

1. **スロークエリ**を探す
2. **explain**を使用し**実行計画**を確認する
3. チューニングを行う

具体的なチューニング方法は、以下の３つになります。
### [SQLを書き換える]
- **サブクエリ**をできる限り**JOIN句**に置き換える
- **ループ回数**を少なくする（**N+1問題**があれば絶対に修正する）
- **大量データ**を**更新する**際は、**バルクインサート**を行う

### [indexの追加・削除]

> テーブルの情報を探す時に検索の対象としてよく使用するカラムの値だけを取り出して検索しやすいようにしておいたものです。
> [indexとは](https://www.dbonline.jp/sqlite/index/index1.html)

#### indexを貼る際のポイント
- **カーディナリティの高い**（不特定多数のデータが想定される）カラムを選択します。
- 複合インデックスのカラムの**順**に注意が必要です。順によって**インデックスの内容**が変わります。
- 更新性能・キャッシュ効率が低下するので、**必要なものだけ**貼ります。無闇に貼ってはいけません。

### [データ型の見直し]
- テーブルに設定したデータ型と入力したデータ型が**一致**しているか確認が必要です。 型が異なっていた場合、本来は必要のない**無駄な型変換処理**が行われてしまいます。
- この型変換の処理は、**暗黙的**に行われてしまうので、発見が少し難しいです。

## 4. DBチューニング
以下の記事がとても参考になりました。
  > [MySQLパフォーマンスチューニング -my.cnfの見直し](https://qiita.com/mamy1326/items/9c5eaee3c986cff65a55)

DBには、MySQLを始めとする様々なものが存在しますが、**どのDB**でも**似たような設定**を行うことが可能です。今回は、開発環境で使用している**MySQL**を中心に調査しました。

※またPostgreSQLは、[こちら](https://qiita.com/cuzic/items/f9b846e6171a54079d77)の記事が参考になります。

### MySQLパフォーマンスチューニング -my.cnfの見直し
チューニングのポイントは以下の通りです。

- **スロークエリ**が発生していないか？
- mysqlの**メモリ**が正しく割り当てられていないか？
- mysqlの**ログ設定**が適切であるか？
- **max_connection**の設定が適切であるか？

Mysqlのmy.cofが**デフォルト**の設定であれば、これらを設定するだけで**大幅な改善**が可能です。

### 初期の設定や運用が大変...
- 上記の設定を行うことにより、性能改善は十分に見込まれます。
- しかし、プロダクトの状況に応じ、ベストなパフォーマンスを**継続的に維持する**方法としては、あまり現実的ではありません...
- もっと楽な良い方法はないのかと.....

と思い調べていたら、``AWS Aurora``にたどり着きました。ちょうど、本番環境ではAuroraを使用するようなので少し調べてみました。

## 5. auroraについて

> Amazon Aurora は、MySQL および PostgreSQL と互換性のあるクラウド向けのリレーショナルデータベースであり、従来のエンタープライズデータベースのパフォーマンスと可用性に加え、オープンソースデータベースのシンプルさとコスト効率性も兼ね備えています。

> [公式 Amazon Aurora](https://aws.amazon.com/jp/rds/aurora/)

### auroraとは
- **クラウド向けRDB**
- **MySQL**および**PostgreSQL**と互換性あり
- 標準的なMySQLと比べ、**最大５倍**の性能差、PostgreSQLと比べ、**最大3倍**の性能差
- 従来の商用DBと同様なセキュリティ、可用性、信頼性を**１０分の１**のコストで実現

**費用面**以外で悪く書いてある記事が全く見当たらなかったです....笑
Amazonさんが本気を出したみたいです。記事によっては、「**Auroraに合わせて**設計を行った方が良い」とまで書かれている記事もありました。

### メリット
主なメリットは以下の通りです。

#### [クエリのスループットの向上]
```
- CPUを効率的に利用
- 分散ロック機構やQueryChacheの改善による性能向上
```

#### [ディスクの可用性の向上]
    - オートスケーリング機能
    - 容易にバックアップが可能

#### [複数サーバにシャーディング]
    - 複数の小さいDBを１つにまとめる

### チューニング方法
#### [前提]
- **デフォルト**の**パラメータグループ**を使用することで、**十分な高パフォーマンス**を実現することができます。
- さらに、高パフォーマンスを実現するためには、主に以下の２つの方法があります。

#### [方法]
#### 1. 適切なインスタンスタイプを選択

サービスの規模に合わせた**適切なインスタンスタイプ**を選択することで、よりパフォーマンスが最大化されます。

#### 2. 一つのトランザクションで大量の更新や削除を行なったり、大量のデータのシーケンシャルリードを行う場合
auroraの**アーキテクチャに合わせて**クエリを実行することで性能を向上させることができます。
    トランザクションが並列に実行されるワークロード向けにチューニングされているため、**クエリを分割**することで、**並列実行が可能**になり性能が向上します。

## 6. APIサーバ側のチューニングについて
開発を進めていきますと、最初の設計時に想定できなかった大きな仕様変更やバグの発生などが必ず発生します。その際に、**パフォーマンスの低下**に繋がるような**ボトルネック**も必ず生まれます。そのため、決まったチューニング方法はありません。SQLやDBチューニングとは異なり、**泥臭いもの**になりやすいです。

チューニングというより、**性能改善**を目的とした**リファクタリング**に近いかと思います。

### APIサーバとDBのロジックの比率
- 設計段階で議論すべき問題の一つだと思います。
- **全体の設計**を考慮しないといけないため、他のチューニングと比較すると、とても難しいです。

```
[判断材料]
- 仕様
- 開発チームの技術レベル
- プロダクトフェーズ
- 好み ...など
```
簡単に書き出してみましたが、これらを**パフォーマンス面**と天秤に掛けて判断するのは、今の自分ではなかなか難しそうです....

### 不要なクエリを削除
システム上で**不要なクエリ**を発行していないか確認し削除します。

- SQLチューニングと並行して行うことになると思っています。地道で特別な知識は必要ないですが、開発規模が**大きくなればなるほど必要**になるはずです。
- 特に、**ORM**を使用している際には、時間をかけて行う価値はあると思います！！実装する際に、**想定外のクエリ**ばかり発行されたので......

## まとめ
- **DBとAPIサーバ**の**パフォーマンスチューニング**を行う際のイメージが着きました。
- また、**パフォーマンスチューニング**には**終わりがない**ため、**短時間**で**効果的**なチューニングが大切であることが分かりました。
- 次は**フロント側**のパフォーマンスチューニングについてもまとめてみたいと思います。

## 参考URL
- [ヤフー社内でやってるMySQLチューニングセミナー大公開](https://www.slideshare.net/techblogyahoo/mysql-58540246)
- [AuroraかRDSどちらを選ぶべきか比較する話をDevelopers.IO 2019 in OSAKAでしました](https://dev.classmethod.jp/cloud/aws/developers-io-2019-in-osaka-aurora-or-rds/)
- [MySQLクエリーチューニングことはじめ](https://thinkit.co.jp/article/9549)
- [MySQLを高速化するパフォーマンスチューニング入門](https://proengineer.internous.co.jp/content/columnfeature/7104)
- [Amazon Auroraの良さについてまとめてみた](https://tech.connehito.com/entry/2018/08/02/162233)
- [[Aurora事例祭り]Amazon Aurora を使いこなすためのベストプラクティス](https://www.slideshare.net/AmazonWebServicesJapan/auroraamazon-aurora)
- [Amazon Auroraを真に理解するための性能検証](http://blog.father.gedow.net/2015/11/05/amazon-aurora-benchmark/)